Z-Indexを設定してSilverlightで要素を前面に出すためにオンラインで見つけているすべてのドキュメントと例は、Canvas要素をコンテナとして使用しています。
私のアイテムは、DataTemplateのItemsControlコンテナー内のBorder要素です。私は、MouseEnterイベントとMouseLeaveイベントを使用して、ScaleTransform.ScaleXとScaleTransform.ScaleYでアニメーションをトリガーし、ホバーすると拡大するようにします。サイズ変更され、コンテナ内の他のアイテムと同じスペースを占めるため、最近追加されたアイテムは、現在のサイズ変更アイテムとは対照的に、古いアイテムと重なっています。現在のアイテムをコード内で前方に移動して、サイズを変更したときに他のすべてのアイテムと重なるようにアニメーションをトリガーするクリーンな方法はありますか?
私はこれに対処しなければなりませんでした。
カスタムコントロールのインスタンスに設定されたItemTemplateを持つItemsControlがあるとします。そのコントロール内で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 );
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
〜99999(IsMouseOver
がtrue
の場合)。 ContentPresenter
はBorder
のパネルの子であるため、ContentPresenter
ではなくItemsControl
になければなりません。
残念ながら、このプロパティはまだSilverlightに到達していないと思います...
GridをLayoutRootとして使用するコントロールの場合、コントロール自体の中でそれと同じくらい簡単なことができます。
Canvas.SetZIndex(this, 999);
最初にすべての子要素の最大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());
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;
}
まず、添付プロパティZindexは Canvas で定義されているため、Panelの他の派生物では使用できません。
ItemsControlは、リストの順序に従ってサブ要素を順序付けます。スタックの一番下にある最初のアイテムと一番上にある最後のアイテム。それが与えられたら、あなたがしなければならないことは、選択されたアイテムがリストの一番下にあることを確認することです。
まず、注文用のインターフェースを作成します。このような:
interface IOrderable
{
int theZOrder{get;set;}
}
これを、表示しているクラスに実装します。
アイテムを前面に表示する場合は、アイテムに高い数字を付け、他のアイテムには小さい数字を付けます。
残っているのは実際の順序です。次のようなものを追加すると、設定が完了します。
ItemsCont.ItemsSource =
ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder);
この方法で要素のzインデックスを設定します
var zIndex =
((Panel) element.Parent)
.Children.Cast<UIElement>()
.Max(child => Canvas.GetZIndex(child))
;
zIndex++;
Canvas.SetZIndex(element, zIndex);