首页 > 解决方案 > 如何获得 ContentPresenter 的父 ItemsControl?

问题描述

我有一个从这个问题的答案修改的拖拽行为。几乎一切正常,除非我将形状拖过其他形状。这是我的 ItemsControl 的 XAML:

<ItemsControl x:Name="audioDisplayItemsControl" 
                      ItemsSource="{Binding Shapes}">
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type ct:Rectangle}">
                    <Rectangle Width="{Binding Width}"
                               Height="{Binding Height}"
                               Fill="Black"
                               IsManipulationEnabled="True"/>
                </DataTemplate>
                <DataTemplate DataType="{x:Type ct:Line}">
                    <!-- Points reletive to ItemContainer -->
                    <Line X1="0"
                          Y1="0"
                          X2="0"
                          Y2="{Binding Length}"
                          Stroke="Gray"
                          StrokeThickness="2"
                          StrokeDashArray="4 1"/>
                </DataTemplate>
                <DataTemplate DataType="{x:Type ct:LabeledLine}">
                    <Grid>
                        <!-- Points reletive to ContentPresenter-->
                        <Line X1="0"
                              Y1="0"
                              X2="0"
                              Y2="{Binding Length}"
                              Stroke="Red"
                              StrokeThickness="2"/>
                        <TextBlock Margin="4,1,0,0" Foreground="White">
                            <Run Text="("/>
                            <Run Text="{Binding Num}"/>
                            <Run Text=") "/>
                            <Run Text="{Binding Title}"/>
                        </TextBlock>
                    </Grid>
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    
                    <Canvas>
                        <Canvas.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="Black"/>
                                    <GradientStop Color="Black" Offset="0.30"/>
                                    <GradientStop Color="Green" Offset="0.33"/>
                                    <GradientStop Color="Green" Offset="0.67"/>
                                    <GradientStop Color="Black" Offset="0.7"/>
                                    <GradientStop Color="Black" Offset="1"/>
                            </LinearGradientBrush>
                        </Canvas.Background>
                    </Canvas>
                    
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Top" Value="{Binding Top, Mode=TwoWay}"/>
                    <Setter Property="Canvas.Left" Value="{Binding Left, Mode=TwoWay}"/>
                    <Setter Property="Panel.ZIndex" Value="{Binding ZIndex}"/>
                    <Setter Property="ct:DragBehavior.Drag" Value="{Binding CanDrag}"/>  <----- DragBehavior attached here
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>

这是我ItemsControl在添加形状列表之前的样子 空白项控制

添加形状后,它看起来像这样 在此处输入图像描述

只有红线 ( ct:LabeledLine) 是可拖动的,并且只能沿 x 轴拖动。我的问题是当我将一条红线拖过右侧的红线时,如图所示

在此处输入图像描述

“(0) New 0”的红线越过了“(1) New 1”的红线,但没有越过“(1) New 1”的文本。由于 (0) 是在 (1) 之前添加的,因此ContentPresenterfor (0) 在ContentPresenterfor (1) 之后。现在我不能再拖动 (0),除非我将 (1) 移开。这是因为拖动行为附加到contentPresenter,而不是红线。

MouseLeftButtonUp事件中,我可以得到ContentPresenter(它只是发件人),但我需要得到父ItemsControl级,这样我才能得到它的子级列表,按它们的 x 位置值对它们进行排序,并ZIndex根据它们的排序顺序进行分配。我认为这应该可以解决我的问题。

我只是不知道如何得到父母ItemsControl

标签: c#wpf

解决方案


您可以使用VisualTreeHelper.GetParent.

当我需要做这样的事情时,这是我使用的一种方法:

Public Function FindVisualParent(Of ParentType As DependencyObject)(obj As DependencyObject) As ParentType
    Dim Parent As DependencyObject = obj

    Do Until Parent Is Nothing OrElse TypeOf Parent Is ParentType
        If TypeOf Parent IsNot Visual AndAlso TypeOf Parent IsNot Media3D.Visual3D AndAlso TypeOf Parent Is FrameworkContentElement Then
            Parent = DirectCast(Parent, FrameworkContentElement).Parent
        Else
            Parent = VisualTreeHelper.GetParent(Parent)
        End If
    Loop

    Return Parent
End Function

我花时间将以上内容转换为 C#:

public ParentType FindVisualParent<ParentType>(DependencyObject obj) where ParentType : DependencyObject
{
    DependencyObject Parent = obj;

    while (Parent != null && !(Parent is ParentType))
    {
        if (Parent is FrameworkContentElement contentElement)
            Parent = contentElement.Parent;
        else
            Parent = VisualTreeHelper.GetParent(Parent);
    }

    return (ParentType)Parent;
}

推荐阅读