C# 带到前面

C# 带到前面,c#,wpf,z-index,C#,Wpf,Z Index,我有一个ItemsControl,它使用画布作为ItemsPanel。itemsTemplate承载一个自定义控件。单击控件时,我希望它“移到前面”。我知道我可以控制ZIndex这样做: private void MyControl_PreviewMouseDown(object sender, MouseButtonEventArgs e) { if(((FrameworkElement)sender).TemplatedParent==null) return; Conte

我有一个ItemsControl,它使用画布作为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 0,因此将根据列表中的位置采用默认顺序

例如:

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

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


有没有一种简单的方法来处理这个问题,或者我是否需要跟踪顺序并自行递增或递减一个任意值,例如99?

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


丑陋,但到目前为止,我没有更好的解决方案

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

鼠标按下时,将选定控件上的Z索引设置为非常高的数字。 将静态int-Zindex初始化为0。 鼠标悬停时,将Z索引设置为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索引,并从所有控件和Zindex计数器上的z索引中减去它。

最简单的方法是只枚举一次所有项,如果我们通过了前面的z索引,则只减少z索引。这确保了最底层项目的z索引始终为0,最后一个项目的z索引为(计数-1),每个项目的z索引相差一个整数1

如果每次都增加(或减少)一个,将一个设置为带到最前面,则z指数可能永远不会从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;
}
//如果您还没有要放在前面的项目(或目标项目)的z索引。。。
var i=YourItem.Z;
foreach(项目列表中的var j)
{
//当前项按顺序出现在目标项之后
如果(j.Z>i)
{
j、 Z--;
}
else if(j.Z

这假设您将对象列表绑定到
ItemsControl
,并且对象具有绑定到
面板的
Z
属性。ZIndex
属性位于
itemsContainerStyle

是的,我以前做过,但在这种情况下,我的控件没有引用承载它的控件。这一切都是通过使用MVVM进行数据绑定来完成的。我更喜欢将控件封装起来。为了溢出
ZIndex
,您需要单击
int.MaxValue
,即使有人以每秒10次、全天候的惊人速度单击,也需要近7年的连续、不间断的超级单击!所以我觉得没什么好担心的。此外,静态成员
ZIndex
的初始值不应为
0
,因为第一次单击将分配
1
,该值可能低于另一个控件的
ZIndex
。最好用
1000
左右来初始化它,以确保此方法从第一次单击开始就可以工作。在我(稍微不同)的情况下,这也对我起了作用。我删除了每个函数开头的if()检查,并将presenter更改为声明:
ContentControl presenter=(ContentControl)((FrameworkElement)sender)。谢谢你的解决方案!