C# 在 Silverlight/WPF 中前移元素(Z 索引)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/630006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bring element forward (Z Index) in Silverlight/WPF
提问by Rich
All the documentation and examples I'm finding online for setting Z-Index to bring an element forward in Silverlight are using a Canvas element as a container.
我在网上找到的所有用于设置 Z-Index 以在 Silverlight 中引入元素的文档和示例都使用 Canvas 元素作为容器。
My items are Border elements inside of an ItemsControl container in a DataTemplate. I'm using the MouseEnter and MouseLeave events to trigger an animation on the ScaleTransform.ScaleX and ScaleTransform.ScaleY so they grow when hovered. As they're resized and occupying the same space as other items in the container(s), the most recently added items are overlapping the older items (as opposed to the currently resizing item). Is there a CLEAN way to bring the current item forward in code where I trigger my animation so that they overlap all other items when they're resized?
我的项目是 DataTemplate 中 ItemsControl 容器内的 Border 元素。我正在使用 MouseEnter 和 MouseLeave 事件来触发 ScaleTransform.ScaleX 和 ScaleTransform.ScaleY 上的动画,以便它们在悬停时增长。由于它们被调整大小并与容器中的其他项目占据相同的空间,最近添加的项目与旧项目重叠(与当前调整大小的项目相反)。是否有一种干净的方法可以在我触发动画的代码中将当前项目向前推进,以便它们在调整大小时与所有其他项目重叠?
回答by Sorskoot
First, the attached property Zindex is defined in Canvasand thus is not available in other derivatives of Panel.
首先,附加属性 Zindex 在Canvas 中定义,因此在 Panel 的其他派生物中不可用。
The ItemsControl orders the subelements according to the order of the list. The first Item at the bottom of the stack and the last on top. With that given, all you have to do is making sure the selected item is on bottom of the list.
ItemsControl 根据列表的顺序对子元素进行排序。堆栈底部的第一个 Item 和顶部的最后一个。有了这个,您所要做的就是确保所选项目位于列表底部。
First create an interface for the ordering. Like this:
首先创建一个用于排序的接口。像这样:
interface IOrderable
{
int theZOrder{get;set;}
}
Now implement this in the class you're showing.
现在在您正在展示的课程中实现这一点。
When you want to bring a item to the front, give it a high number and give all others a low number.
当你想把一个项目放在前面时,给它一个高的数字,给所有其他的一个低的数字。
Al there's left is the actual ordering. Add something like this and you're set:
剩下的就是实际的订购。添加这样的东西,你就设置好了:
ItemsCont.ItemsSource =
ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder);
回答by Robert Macnee
In WPF there is the Panel.ZIndexproperty that you can set in a trigger:
在 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>
In the Style
for ContentPresenter
we set the Panel.ZIndex
to 99999 when IsMouseOver
is true
. It must be on the ContentPresenter
and not the Border
because the ContentPresenter
s are children of the ItemsControl
's panel.
在Style
为ContentPresenter
我们设置Panel.ZIndex
到99999的时候IsMouseOver
是true
。它必须在 theContentPresenter
而不是 theBorder
因为ContentPresenter
s 是 theItemsControl
面板的子级。
Unfortunately I don't think this property has made it to Silverlight yet...
不幸的是,我认为这个属性还没有进入 Silverlight ......
回答by user127111
I've had to deal with this.
我不得不处理这个问题。
Say you have an ItemsControl with an ItemTemplate set to an instance of a custom control. Within that control you do Canvas.SetZIndex(this, 99). It won't work, because "this" is not the immediate child of the ItemsControl's ItemsPanel. The ItemsControl creates a ContentPresenter for each item, drops that into the ItemsPanel, and renders the ItemTemplate within the ContentPresenter.
假设您有一个 ItemsControl,其中 ItemTemplate 设置为自定义控件的实例。在该控件中,您可以执行 Canvas.SetZIndex(this, 99)。它不起作用,因为“this”不是 ItemsControl 的 ItemsPanel 的直接子项。ItemsControl 为每个项目创建一个 ContentPresenter,将其放入 ItemsPanel,并在 ContentPresenter 中呈现 ItemTemplate。
So, if you want to change the ZIndex within your control, you have to find its ContentPresenter, and change the ZIndex on that. One way is...
因此,如果您想更改控件中的 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 );
回答by charlierlee
Html works the same way. All the list items must be siblings if you want to lay them out in layers.
Html 的工作方式相同。如果要分层排列,所有列表项必须是同级项。
I extended the code above so that it will stop if it finds (for example) an ItemsPresenter. If the ContentPresenter doesn't show itself between here and the ItemsPresenter, then fall back on my original code.
我扩展了上面的代码,以便它在找到(例如)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;
}
回答by Micha? Suliga
For a control that uses the Grid as LayoutRoot you can just do something as simple as that within a control itself:
对于使用 Grid 作为 LayoutRoot 的控件,您可以执行与控件本身一样简单的操作:
Canvas.SetZIndex(this, 999);
回答by Omid-RH
set zIndex of your element in this way
以这种方式设置元素的 zIndex
var zIndex =
((Panel) element.Parent)
.Children.Cast<UIElement>()
.Max(child => Canvas.GetZIndex(child))
;
zIndex++;
Canvas.SetZIndex(element, zIndex);
- maybe you need to check if zIndex is equal to int.MaxValue then reset "ZIndex"s.
- but this almost never happens
- 也许您需要检查 zIndex 是否等于 int.MaxValue 然后重置“ZIndex”。
- 但这几乎从未发生过
回答by Kishore Kumar
First find the Maximum ZIndex of all its child elements and then set the new ZIndex.
首先找到其所有子元素的最大 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;
}
Then assign
然后赋值
Canvas.SetZIndex(child, MaxZIndex());