C# 在Silverlight/WPF中向前推进元素(Z索引)

C# 在Silverlight/WPF中向前推进元素(Z索引),c#,wpf,silverlight,xaml,C#,Wpf,Silverlight,Xaml,我在网上找到的所有文档和示例都是使用Canvas元素作为容器来设置Z-Index以在Silverlight中向前推进元素 My items是DataTemplate中ItemsControl容器内的边框元素。我正在使用MouseEnter和MouseLeave事件在ScaleTransform.ScaleX和ScaleTransform.ScaleY上触发动画,以便它们在悬停时增长。当它们调整大小并与容器中的其他项目占用相同的空间时,最近添加的项目与旧项目重叠(与当前调整大小的项目相反)。在我触

我在网上找到的所有文档和示例都是使用Canvas元素作为容器来设置Z-Index以在Silverlight中向前推进元素


My items是DataTemplate中ItemsControl容器内的边框元素。我正在使用MouseEnter和MouseLeave事件在ScaleTransform.ScaleX和ScaleTransform.ScaleY上触发动画,以便它们在悬停时增长。当它们调整大小并与容器中的其他项目占用相同的空间时,最近添加的项目与旧项目重叠(与当前调整大小的项目相反)。在我触发动画的代码中,是否有一种干净的方法使当前项向前移动,以便它们在调整大小时与所有其他项重叠?

首先,附加的属性Zindex在中定义,因此在面板的其他派生版本中不可用

ItemsControl根据列表的顺序对子元素进行排序。堆栈底部的第一项和顶部的最后一项。在给定条件下,您所要做的就是确保所选项目位于列表的底部

首先为订单创建一个接口。像这样:

interface IOrderable
    {
        int theZOrder{get;set;}
    }
现在在你展示的类中实现这个

当你想把一个项目放在前面时,给它一个高的数字,给所有其他项目一个低的数字

剩下的是实际的订单。添加这样的内容,您就可以:

ItemsCont.ItemsSource = 
            ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder);
在WPF中,可以在触发器中设置以下属性:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.Resources>
        <x:Array x:Key="colors" Type="{x:Type Color}">
            <Color>Green</Color>
            <Color>Red</Color>
            <Color>Blue</Color>
            <Color>Orange</Color>
            <Color>Yellow</Color>
            <Color>Violet</Color>
        </x:Array>
        <DataTemplate DataType="{x:Type Color}">
            <Border x:Name="brd" Height="20" Width="20">
                <Border.Background>
                    <SolidColorBrush Color="{Binding}"/>
                </Border.Background>
                <Border.RenderTransform>
                    <ScaleTransform CenterX="10" CenterY="10"/>
                </Border.RenderTransform>
                <Border.Style>
                    <Style TargetType="{x:Type Border}">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="BorderThickness" Value="2"/>
                                <Setter Property="BorderBrush" Value="Black"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
                <Border.Triggers>
                    <EventTrigger RoutedEvent="Border.MouseEnter">
                        <BeginStoryboard>
                            <Storyboard>
                               <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="brd" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.5"/>
                               <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="brd" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.5"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="Border.MouseLeave">
                        <BeginStoryboard>
                            <Storyboard>
                               <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="brd" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1"/>
                               <DoubleAnimation Duration="0:0:0.5" Storyboard.TargetName="brd" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1"/>
                            </Storyboard>
                        </BeginStoryboard>
                  </EventTrigger>
                </Border.Triggers>
            </Border>
        </DataTemplate>
    <Style TargetType="{x:Type ContentPresenter}">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Panel.ZIndex" Value="99999"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    </Grid.Resources>
    <ItemsControl ItemsSource="{StaticResource colors}" Margin="20" Width="40">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

绿色
红色
蓝色
橙色
黄色的
紫罗兰色
ContentPresenter
Style
中,当
IsMouseOver
true
时,我们将
面板.ZIndex
设置为99999。它必须位于
ContentPresenter
上,而不是
边框上,因为
ContentPresenter
ItemsControl
面板的子项


不幸的是,我认为这家酒店还没有到达Silverlight…

我不得不处理这个问题

假设您有一个ItemsControl,其中ItemTemplate设置为自定义控件的实例。在该控件中,您可以执行Canvas.SetZIndex(这个,99)。它不会工作,因为“this”不是ItemsControl的ItemsPanel的直接子级。ItemsControl为每个项目创建一个ContentPresenter,将其放入ItemsPanel,并在ContentPresenter中呈现ItemTemplate

因此,如果要更改控件中的ZIndex,必须找到它的ContentPresenter,并更改该控件上的ZIndex。一种方法是

        public static T FindVisualParent<T>( this DependencyObject obj )
        where T : DependencyObject
    {
        DependencyObject parent = VisualTreeHelper.GetParent( obj );
        while ( parent != null )
        {
            T typed = parent as T;
            if ( typed != null )
            {
                return typed;
            }
            parent = VisualTreeHelper.GetParent( parent );
        }
        return null;
    }
                ContentPresenter foo = this.FindVisualParent<ContentPresenter>();
            Canvas.SetZIndex( foo, 99 );
public static T FindVisualParent(此DependencyObject obj)
其中T:DependencyObject
{
DependencyObject parent=VisualTreeHelper.GetParent(obj);
while(父级!=null)
{
T类型=作为T的父级;
如果(已键入!=null)
{
返回类型;
}
父级=VisualTreeHelper.GetParent(父级);
}
返回null;
}
ContentPresenter foo=this.FindVisualParent();
Canvas.SetZIndex(foo,99);

Html的工作方式与此相同。如果要在图层中布局,所有列表项都必须是同级

我扩展了上面的代码,以便在找到(例如)ItemsPresenter时停止。如果ContentPresenter没有在此处和ItemsPresenter之间显示,那么请使用我的原始代码

void setZindex(MyLayeredType layeredObj, int index) 
{
    ContentPresenter sibbling = 
    FindVisualParent<ContentPresenter, ItemsPresenter>(layeredObj);
    if (sibbling != null)
    {
        sibbling.SetValue(Canvas.ZIndexProperty, index);
    }
    else
    {
        layeredObj.SetValue(Canvas.ZIndexProperty, index);
    }
}

public static T FindVisualParent<T,C>(this DependencyObject obj)
where T : DependencyObject
where C : DependencyObject
{
    DependencyObject parent = VisualTreeHelper.GetParent(obj);
    while (parent != null)
    {
        T typed = parent as T;
        if (typed != null)
        {
            return typed;
        }
        C ceiling = parent as C;
        if (ceiling != null)
            return null;
        parent = VisualTreeHelper.GetParent(parent);
    }
    return null;
}
void setZindex(MyLayeredType layeredObj,int index)
{
ContentPresenter同级=
FindVisualParent(layeredObj);
if(同级!=null)
{
SetValue(Canvas.ZIndexProperty,index);
}
其他的
{
layeredObj.SetValue(Canvas.ZIndexProperty,index);
}
}
公共静态T FindVisualParent(此DependencyObject obj)
其中T:DependencyObject
其中C:DependencyObject
{
DependencyObject parent=VisualTreeHelper.GetParent(obj);
while(父级!=null)
{
T类型=作为T的父级;
如果(已键入!=null)
{
返回类型;
}
C上限=作为C的父级;
如果(上限!=null)
返回null;
父级=VisualTreeHelper.GetParent(父级);
}
返回null;
}

对于使用网格作为LayoutRoot的控件,您只需在控件本身内执行一些简单的操作即可:

Canvas.SetZIndex(this, 999);

以这种方式设置元素的zIndex

var zIndex = 
    ((Panel) element.Parent)
    .Children.Cast<UIElement>()
    .Max(child => Canvas.GetZIndex(child))
    ;

zIndex++;

Canvas.SetZIndex(element, zIndex);
var zIndex=
((面板)element.Parent)
.Children.Cast()
.Max(child=>Canvas.GetZIndex(child))
;
zIndex++;
Canvas.SetZIndex(元素,zIndex);
  • 也许您需要检查zIndex是否等于int.MaxValue,然后重置“zIndex”s
  • 但这几乎从未发生过

首先找到其所有子元素的最大ZIndex,然后设置新的ZIndex

private int MaxZIndex()
{
    int iMax = 0;
    foreach (UIElement element in JIMSCanvas.Children)
    {            
        int iZIndex=Canvas.GetZIndex(element);
        if(iZIndex>iMax)
        {
            iMax = iZIndex;
        }
    }
    return iMax+1;
}
然后分配

Canvas.SetZIndex(child, MaxZIndex());
我一开始就想到了,