Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bring element forward (Z Index) in Silverlight/WPF

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?

like image 741
Rich Avatar asked Mar 10 '09 12:03

Rich


4 Answers

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 ContentPresenters are children of the ItemsControl's panel.

Unfortunately I don't think this property has made it to Silverlight yet...

like image 20
Robert Macnee Avatar answered Oct 23 '22 16:10

Robert Macnee


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 );
like image 158
user127111 Avatar answered Oct 23 '22 16:10

user127111


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);
like image 3
Michał Suliga Avatar answered Oct 23 '22 15:10

Michał Suliga


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());
like image 3
Kishore Kumar Avatar answered Oct 23 '22 15:10

Kishore Kumar