web-dev-qa-db-ja.com

Silverlight / WPFで要素を前面に移動(Zインデックス)

Z-Indexを設定してSilverlightで要素を前面に出すためにオンラインで見つけているすべてのドキュメントと例は、Canvas要素をコンテナとして使用しています。

私のアイテムは、DataTemplateのItemsControlコンテナー内のBorder要素です。私は、MouseEnterイベントとMouseLeaveイベントを使用して、ScaleTransform.ScaleXとScaleTransform.ScaleYでアニメーションをトリガーし、ホバーすると拡大するようにします。サイズ変更され、コンテナ内の他のアイテムと同じスペースを占めるため、最近追加されたアイテムは、現在のサイズ変更アイテムとは対照的に、古いアイテムと重なっています。現在のアイテムをコード内で前方に移動して、サイズを変更したときに他のすべてのアイテムと重なるようにアニメーションをトリガーするクリーンな方法はありますか?

36
Rich

私はこれに対処しなければなりませんでした。

カスタムコントロールのインスタンスに設定された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 );
34
user127111

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>

StyleContentPresenterでは、Panel.ZIndex〜99999(IsMouseOvertrueの場合)。 ContentPresenterBorderのパネルの子であるため、ContentPresenterではなくItemsControlになければなりません。

残念ながら、このプロパティはまだSilverlightに到達していないと思います...

15
Robert Macnee

GridをLayoutRootとして使用するコントロールの場合、コントロール自体の中でそれと同じくらい簡単なことができます。

Canvas.SetZIndex(this, 999);
3
Michał Suliga

最初にすべての子要素の最大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());
3
Kishore Kumar

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;
}
2
charlierlee

まず、添付プロパティZindexは Canvas で定義されているため、Panelの他の派生物では使用できません。

ItemsControlは、リストの順序に従ってサブ要素を順序付けます。スタックの一番下にある最初のアイテムと一番上にある最後のアイテム。それが与えられたら、あなたがしなければならないことは、選択されたアイテムがリストの一番下にあることを確認することです。

まず、注文用のインターフェースを作成します。このような:

interface IOrderable
    {
        int theZOrder{get;set;}
    }

これを、表示しているクラスに実装します。

アイテムを前面に表示する場合は、アイテムに高い数字を付け、他のアイテムには小さい数字を付けます。

残っているのは実際の順序です。次のようなものを追加すると、設定が完了します。

ItemsCont.ItemsSource = 
            ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder);
2
Sorskoot

この方法で要素のzインデックスを設定します

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

zIndex++;

Canvas.SetZIndex(element, zIndex);
  • しかし、これはほとんど起こりません.
1
Omid-RH