可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
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?
回答1:
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.
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...
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 );
回答2:
In WPF there is the Panel.ZIndex property that you can set in a trigger:
<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.
Unfortunately I don't think this property has made it to Silverlight yet...
回答3:
For a control that uses the Grid as LayoutRoot you can just do something as simple as that within a control itself:
Canvas.SetZIndex(this, 999);
回答4:
First find the Maximum ZIndex of all its child elements and then set the new 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());
回答5:
First, the attached property Zindex is defined in Canvas and thus is not available in other derivatives of 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.
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);
回答6:
Html works the same way. All the list items must be siblings if you want to lay them out in layers.
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.
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;
}
回答7:
set zIndex of your element in this way
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