【问题标题】:Lock zIndex of a ContentPresenter Upon Mouse Enter or Drag Complete在鼠标进入或拖动完成时锁定 ContentPresenter 的 zIndex
【发布时间】:2020-02-14 01:18:35
【问题描述】:

在被Thumb 拖动后,我需要锁定画布/内容控件的 Z 顺序。

在下图中,当鼠标悬停时,“Joe Smith”在其他两个椭圆上方弹出。一旦拖动停止并且鼠标移出,它就会回落到它的值。

我无法在下面显示的设计中找到解决方案,以将其锁定在其他设计之上。


最小可重现示例

我创建了一个包含 xaml、thumb 类和 people 类的所有代码的code gist。所要做的就是创建一个 .Net Core WPF 应用程序并放入代码的 sn-ps 并根据需要在 Xaml 中设置名称间距。


设计 有一个ItemsControl,它的DataTemplateCanvas 定义。 ItemsControl 中的每个内容都有ContentControl,它有一个Thumb,由样式应用。

鼠标进入ContentPresenter 的另一种样式触发器通过将内容的内部GridzIndex 设置为1,将内容临时推入其他zIndex 之上。

如何坚持 zIndex

Xaml

<ItemsControl Margin="10" ItemsSource="{Binding Source={StaticResource People}}">

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="1" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Canvas>
                <ContentControl  Width="100" Height="100" >
                    <Grid>
                        <Ellipse Fill="Silver">
                            <Ellipse.Effect>
                                <DropShadowEffect Color="Black" Direction="320"  ShadowDepth="6"  Opacity="0.5"/>
                            </Ellipse.Effect>
                        </Ellipse>
                        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                            <TextBlock Margin="3,3,3,0" Text="{Binding Path=First}"/>
                            <TextBlock Margin="3,0,3,7" Text="{Binding Path=Last}"/>
                        </StackPanel>
                    </Grid>
                </ContentControl>
            </Canvas>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="{x:Type ContentPresenter}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Grid.ZIndex" Value="1"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

请参阅 Gist 以了解所有支持的类和样式以重现


实际设计

最终目标是拥有一组固定大小的图像,当用户抓住拇指时,图像会向前移动并锁定在其他图像之上。我说如果有另一种方法可以在最小示例设计之上提供答案。

【问题讨论】:

  • 为了实现类似的效果,我使用 Canvas 作为 ItemsPanelTemplate。为了排列 Canvas ItemsPanel 中的项目,我使用了 Canvas.Left 和 Canvas.Top。为了使最后一个交互项目的 ZIndex 位于顶部,我会在每次鼠标单击/拖动完成时更改此单击项目的 Canvas.ZIndex。最高的 ZIndex 被存储并在每次操作时递增。
  • @Insane 我想知道我是否将自己设计到这个洞里。如果这不适合我,您对 tracked 画布的建议是值得探索的。 &thx 如果没有别的,通过该事件查看当前拖动的项目是可行的,并在后面的代码中重置保留列表中的其他项目让我暂停。
  • @Insane 我发现了一个不同的解决方法,它不需要保存最高 ZIndex。如果有兴趣,请查看提供的答案。

标签: c# wpf z-index itemscontrol .net-core-3.1


【解决方案1】:

在我的ItemsControl 中,我将ItemsPanelTemplate 更改为Canvas,例如

<ItemsPanelTemplate>
    <Canvas x:Name="MainCanvas" />
</ItemsPanelTemplate>

当查看用户单击ContentControl 的可视化树时,它有一个Canvas 的父级,该父级有一个ContentPresenter 和顶级Canvas,例如(见命名MainCanvas):

我将ContentControl 更改为MouseEnter 事件:

<ContentControl  Width="100" Height="100" MouseEnter="EnterMouse">
   <Grid>
       <Ellipse Fill="Silver">

在该方法中,我需要找到名为“MainCanvas”Canvas 并枚举其所有子 ContentPresenters 并提取最大 ZIndex,然后将我的 ContentControl(如上图蓝色所示)设置为该 ZIndex值加 1。

这里是提取必要父母的代码:

private void EnterMouse(object sender, MouseEventArgs e)
{
    if (sender is ContentControl cc)
    {
        var cpParent = FindParent<ContentPresenter>(cc);
        var p2 = FindParent<Canvas>(cpParent);

        var max = p2.Children.Cast<UIElement>().Max(control => Panel.GetZIndex(control));
        Panel.SetZIndex(cpParent, max + 1);
    }
}

private T FindParent<T>(DependencyObject child) where T : DependencyObject
{
    DependencyObject immediateParent = VisualTreeHelper.GetParent(child);

    T parent = immediateParent as T;

    return parent ?? FindParent<T>(immediateParent);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    • 2016-01-07
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    • 2019-04-06
    相关资源
    最近更新 更多