我在网上找到的用于设置Z-Index以在Silverlight中引入元素的所有文档和示例都使用Canvas元素作为容器。
我的项目是DataTemplate中ItemsControl容器内的Border元素。我正在使用MouseEnter和MouseLeave事件在ScaleTransform.ScaleX和ScaleTransform.ScaleY上触发动画,以便它们在悬停时生长。由于它们已调整大小并占据与容器中其他项目相同的空间,因此最近添加的项目与旧项目重叠(与当前调整大小的项目相对)。有没有一种清洁方法可以将当前项目转发到我触发动画的代码中,以便在调整大小时将它们重叠所有其他项目?
答案 0 :(得分:34)
我不得不处理这件事。
假设您有一个ItemsControl,其中ItemTemplate设置为自定义控件的实例。在该控件中,您可以执行Canvas.SetZIndex(this,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 );
答案 1 :(得分:15)
在WPF中,您可以在触发器中设置Panel.ZIndex属性:
<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>
在Style
ContentPresenter
Panel.ZIndex
IsMouseOver
true
ContentPresenter
为Border
时ContentPresenter
为ItemsControl
。它必须位于{{1}}而不是{{1}},因为{{1}}是{{1}}小组的子级。
不幸的是,我认为这个属性还没有成为Silverlight ...
答案 2 :(得分:3)
对于使用Grid作为LayoutRoot的控件,您可以执行与控件本身一样简单的操作:
Canvas.SetZIndex(this, 999);
答案 3 :(得分:3)
首先找到所有子元素的Maximum 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());
答案 4 :(得分:2)
首先,附加属性Zindex在Canvas中定义,因此在Panel的其他衍生物中不可用。
ItemsControl根据列表的顺序对子元素进行排序。堆栈底部的第一个项目和顶部的最后一个。有了这个,您所要做的就是确保所选项目位于列表的底部。
首先为订购创建一个界面。像这样:
interface IOrderable
{
int theZOrder{get;set;}
}
现在在你正在展示的课程中实现它。
如果您想将物品放在前面,请给它一个较大的数字,并给所有其他物品一个较低的数字。
剩下的是实际订购。添加这样的东西,然后设置:
ItemsCont.ItemsSource =
ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder);
答案 5 :(得分:2)
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;
}
答案 6 :(得分:1)
以这种方式设置z元素的索引
var zIndex =
((Panel) element.Parent)
.Children.Cast<UIElement>()
.Max(child => Canvas.GetZIndex(child))
;
zIndex++;
Canvas.SetZIndex(element, zIndex);