Перенести элемент вперед (индекс Z) в Silverlight / WPF - PullRequest
36 голосов
/ 10 марта 2009

Вся документация и примеры, которые я нахожу в Интернете для настройки Z-Index для продвижения элемента в Silverlight, используют элемент Canvas в качестве контейнера.

Мои элементы - это элементы Border внутри контейнера ItemsControl в DataTemplate. Я использую события MouseEnter и MouseLeave для запуска анимации в ScaleTransform.ScaleX и ScaleTransform.ScaleY, чтобы они росли при наведении. Поскольку они изменяются в размере и занимают то же пространство, что и другие элементы в контейнере (контейнерах), последние добавленные элементы перекрывают более старые элементы (в отличие от текущего элемента с изменяющимся размером). Есть ли ЧИСТЫЙ способ перенести текущий элемент в код, где я запускаю свою анимацию, чтобы они перекрывали все остальные элементы при изменении их размера?

Ответы [ 7 ]

34 голосов
/ 22 июня 2009

Мне приходилось иметь дело с этим.

Скажем, у вас есть ItemsControl с ItemTemplate, установленным на экземпляр пользовательского элемента управления. Внутри этого элемента управления вы делаете Canvas.SetZIndex (this, 99). Это не будет работать, потому что «this» не является непосредственным потомком ItemsPontel ItemsControl. ItemsControl создает ContentPresenter для каждого элемента, помещает его в ItemsPanel и отображает шаблон ItemTemplate в ContentPresenter.

Итак, если вы хотите изменить 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 );
15 голосов
/ 10 марта 2009

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

3 голосов
/ 25 апреля 2012

Сначала найдите Maximum 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 голосов
/ 21 ноября 2010

Для элемента управления, который использует Grid в качестве LayoutRoot, вы можете просто сделать что-то столь же простое, как в самом элементе управления:

Canvas.SetZIndex(this, 999);
2 голосов
/ 30 июля 2010

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 голосов
/ 10 марта 2009

Во-первых, прикрепленное свойство Zindex определено в Canvas и поэтому недоступно в других производных Panel.

ItemsControl упорядочивает подэлементы в соответствии с порядком списка. Первый элемент внизу стека и последний сверху. Учитывая это, все, что вам нужно сделать, это убедиться, что выбранный элемент находится внизу списка.

Сначала создайте интерфейс для оформления заказа. Как это:

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

Теперь реализуйте это в классе, который вы показываете.

Если вы хотите вынести предмет на передний план, присвойте ему большое число, а всем остальным - меньшее.

Все, что осталось - это фактический порядок. Добавьте что-то вроде этого, и все готово:

ItemsCont.ItemsSource = 
            ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder);
1 голос
/ 01 ноября 2011

установить zIndex вашего элемента таким образом

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

zIndex++;

Canvas.SetZIndex(element, zIndex);
  • возможно, вам нужно проверить, равно ли zIndex значению int.MaxValue, а затем сбросить значения ZIndex.
  • но это почти никогда не происходит
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...