【问题标题】:Wpf Bring to FrontWpf 放在前面
【发布时间】:2011-03-28 15:31:39
【问题描述】:

我有一个 ItemsControl,它使用 Canvas 和 ItemsPanel 一样。 itemsTemplate 承载一个自定义控件。单击控件时,我希望它“移到前面”。我知道我可以像这样在我的控件中使用 ZIndex 来做到这一点:

 private void MyControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    if(((FrameworkElement)sender).TemplatedParent==null) return;
    ContentPresenter presenter = (ContentPresenter)((FrameworkElement) sender).TemplatedParent;

    int currentValue = Panel.GetZIndex(presenter);
    Console.WriteLine(currentValue);
    Panel.SetZIndex(presenter, 99);
}

这可以正常工作并设置 ZIndex。但是当我单击 ItemsControl 中的不同控件时,它将获得完全相同的 ZIndex,因此它不会“移动到”另一个控件的前面。

基本上我只想要与 windows 展示相同的行为。

我已经尝试在 PreviewMouseUp 事件中将 ZIndex 设置回 0,这样可以确保单击的控件始终位于顶部,但是由于所有其他控件的 ZIndex 都相同,因此将假定默认顺序基于在列表中的位置。

一个例子:

假设我有 3 个控件,所有控件的 ZIndex 为 0。(因此它们使用默认列表位置。)

如果我点击控件 3,然后是 2,然后是 1。我希望它在 ZOrder 的顶部有 3,然后是 2,然后是 1。但是由于我在 MouseUp 上将 ZIndex 设置为零,所以它会有默认顺序为 1,2,3。

有没有一种简单的方法来处理这个问题,还是我需要自己跟踪订单并递增递减任意值,例如 99?

【问题讨论】:

    标签: c# wpf z-index


    【解决方案1】:

    在我的例子中,我在选定的控件上设置 Zindex,然后枚举所有其他控件并在需要时增加它们的 ZIndex,因为在某些时候你会遇到选定的控件而所有其他控件都不需要更改。

    丑,不过目前还没有更好的解决办法

    【讨论】:

    • 是的,我以前做过,但在这种情况下,我的控件没有引用托管它的控件。这一切都是通过使用 MVVM 的数据绑定来完成的。我更愿意将控件封装起来。
    【解决方案2】:

    我会按照这些思路做一些事情:

    鼠标按下时,将所选控件上的 Z-index 设置为一个非常高的数字。 将静态 int Zindex 初始化为 0。 鼠标向上设置 Z-index 等于 Zindex++

    private static int Zindex = 0;
    
    private void MyControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        if(((FrameworkElement)sender).TemplatedParent==null) return;
        ContentPresenter presenter = (ContentPresenter)((FrameworkElement) sender).TemplatedParent;
    
        int currentValue = Panel.GetZIndex(presenter);
        Console.WriteLine(currentValue);
        Panel.SetZIndex(presenter, Int32.MaxValue);
    }
    
    private void MyControl_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        if(((FrameworkElement)sender).TemplatedParent==null) return;
        ContentPresenter presenter = (ContentPresenter)((FrameworkElement) sender).TemplatedParent;
    
        int currentValue = Panel.GetZIndex(presenter);
        Console.WriteLine(currentValue);
        Panel.SetZIndex(presenter, Zindex++);
    }
    

    如果您的程序应该运行很长时间,您可能会对 Zorder 设置一些上限,因此如果达到上限,您可以找到正在使用的最小 z-index 并将其从所有控件的 z-index 和 Zindex 计数器中减去.

    【讨论】:

    • 为了溢出ZIndex,你需要int.MaxValue点击,即使有人以每秒10次点击的惊人速度点击,24/7,这仍然需要几乎7年连续不间断的超级点击!所以我认为没有什么可担心的。此外,静态成员ZIndex 的初始值不应为0,因为第一次单击将分配1,它可能低于另一个控件的ZIndex。最好使用1000 左右对其进行初始化,以确保此方法从第一次点击开始就起作用。
    • 太棒了。在我(略有不同)的情况下,这也对我有用。我删除了每个函数开头的 if() 检查,并将演示者更改为声明:ContentControl presenter = (ContentControl)((FrameworkElement)sender);。感谢您的解决方案!
    【解决方案3】:

    最简单的方法是仅枚举所有项目一次,并且仅在我们通过了要放在前面的项目时才减小 z-index。这确保了最底部项的 z-index 始终具有 z-index 0,最后一项的 z-index 为 (count - 1),每个项的 z-index 相差一个整数 1。

    如果您每次都增加(或减少)一个,将一个设置为最高,z-index 可能永远不会从 0 开始,最终结果可能与您的喜好过于违反直觉。

    所以每当一个项目应该被带到前面时,你可以像这样枚举这些项目:

    //If you don't already have the z-index of the item to bring to front (or target item)...
    var i = YourItem.Z;
    foreach (var j in YourListOfItems)
    {
        //Current item occurs after target item in sequence
        if (j.Z > i)
        {
            j.Z--;
        }
        else if (j.Z < i)
        {
            //Curent item occurs before target item in sequence; no need to change the z-index
        }
        else j.Z = YourListOfItems.Count - 1;
    }
    

    这假设您将对象列表绑定到ItemsControl,并且对象具有绑定到ItemContainerStyle 中的Panel.ZIndex 属性的Z 属性。

    【讨论】:

      【解决方案4】:

      我有类似的情况,但是当鼠标悬停在控件上时,我需要将项目放在前面。我找到了一个更简单的解决方案:只需通过触发器在 ItemsControl.ItemContainerStyle 中设置 Panel.ZIndex。

      这也可以使用绑定到 viewModel 中的标志的 DataTrigger,例如单击控件时设置的 IsSelected 属性。

                  <ItemsControl Name="ScanPoints" ItemsSource="{Binding ScanPoints}">
                      <ItemsControl.ItemsPanel>
                          <ItemsPanelTemplate>
                              <Canvas></Canvas>
                          </ItemsPanelTemplate>
                      </ItemsControl.ItemsPanel>
                      <ItemsControl.ItemContainerStyle>
                          <Style TargetType="ContentPresenter">
                              <Style.Triggers>
                                  <Trigger Property="IsMouseOver" Value="True">
                                      <Setter Property="Panel.ZIndex" Value="99999"/>
                                  </Trigger>
                                  <Trigger Property="IsMouseOver" Value="False">
                                      <Setter Property="Panel.ZIndex" Value="0"/>
                                  </Trigger>                            
                              </Style.Triggers> 
                          </Style>
                      </ItemsControl.ItemContainerStyle>
                  </ItemsControl>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-05-23
        • 2019-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-26
        • 2011-07-02
        相关资源
        最近更新 更多