it-swarm-pt.tech

Trazer elemento para frente (índice Z) no Silverlight / WPF

Toda a documentação e exemplos que estou encontrando on-line para definir o Z-Index para apresentar um elemento no Silverlight estão usando um elemento Canvas como um contêiner.

Meus itens são elementos de borda dentro de um contêiner ItemsControl em um DataTemplate. Estou usando os eventos MouseEnter e MouseLeave para disparar uma animação nos ScaleTransform.ScaleX e ScaleTransform.ScaleY para que eles cresçam quando pairados. Como eles são redimensionados e ocupam o mesmo espaço que outros itens no (s) contêiner (es), os itens adicionados mais recentemente se sobrepõem aos itens mais antigos (em oposição ao item de redimensionamento atualmente). Existe uma maneira LIMPA de levar o item atual adiante no código em que aciono minha animação para que eles se sobreponham a todos os outros itens quando são redimensionados?

36
Rich

Eu tive que lidar com isso.

Digamos que você tenha um ItemsControl com um ItemTemplate definido como uma instância de um controle personalizado. Nesse controle, você faz Canvas.SetZIndex (isto, 99). Não funcionará, porque "this" não é o filho imediato do ItemsPanel do ItemsControl. O ItemsControl cria um ContentPresenter para cada item, coloca-o no ItemsPanel e renderiza o ItemTemplate no ContentPresenter.

Portanto, se você deseja alterar o ZIndex sob seu controle, você precisa encontrar o ContentPresenter e alterar o ZIndex. Uma maneira é ...

        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

No WPF, existe a propriedade Panel.ZIndex que você pode definir em um gatilho:

<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>

No Style para ContentPresenter, definimos o Panel.ZIndex a 99999 quando IsMouseOver for true. Ele deve estar no ContentPresenter e não no Border porque os ContentPresenters são filhos do painel do ItemsControl.

Infelizmente não acho que essa propriedade tenha chegado ao Silverlight ainda ...

15
Robert Macnee

Para um controle que usa Grid como LayoutRoot, você pode fazer algo tão simples quanto isso dentro de um controle em si:

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

Primeiro, encontre o ZIndex máximo de todos os seus elementos filhos e, em seguida, defina o novo 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;
}

Então atribua

Canvas.SetZIndex(child, MaxZIndex());
3
Kishore Kumar

Html funciona da mesma maneira. Todos os itens da lista devem ser irmãos, se você deseja colocá-los em camadas.

Estendi o código acima para que ele pare se encontrar (por exemplo) um ItemsPresenter. Se o ContentPresenter não aparecer entre aqui e o ItemsPresenter, volte ao meu código original.

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

Primeiro, a propriedade anexada Zindex é definida em Canvas e, portanto, não está disponível em outros derivados do Panel.

O ItemsControl ordena os subelementos de acordo com a ordem da lista. O primeiro item na parte inferior da pilha e o último na parte superior. Com isso, tudo o que você precisa fazer é garantir que o item selecionado esteja no final da lista.

Primeiro, crie uma interface para o pedido. Como isso:

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

Agora implemente isso na classe que você está mostrando.

Quando quiser trazer um item para a frente, atribua um número alto e um número baixo a todos os outros.

Tudo o que resta é o pedido real. Adicione algo assim e você está pronto:

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

configure z Índice do seu elemento dessa maneira

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

zIndex++;

Canvas.SetZIndex(element, zIndex);
  • mas isso quase nunca acontece.
1
Omid-RH