2009-03-10 9 views
36

Cała dokumentacja i przykłady, które znajduję w trybie online do ustawiania Z-Index w celu wprowadzenia elementu do przodu w Silverlight, używają elementu Canvas jako kontenera.Przesunąć element do przodu (indeks Z) w Silverlight/WPF

Moje elementy to elementy obramowania w kontenerze ItemsControl w DataTemplate. Używam zdarzeń MouseEnter i MouseLeave do wyzwalania animacji w skalach ScaleTransform.ScaleX i ScaleTransform.ScaleY, aby rosły po ukryciu. Podczas zmiany rozmiaru i zajmowania tej samej przestrzeni co inne elementy w kontenerach, ostatnio dodane elementy nakładają się na starsze elementy (w przeciwieństwie do aktualnie zmienianego elementu). Czy istnieje CZYSTY sposób na przeniesienie bieżącego elementu do przodu w kodzie, w którym uruchamiam animację, aby nakładały się na wszystkie inne elementy podczas zmiany rozmiaru?

Odpowiedz

2

Po pierwsze, dołączona właściwość Zindex jest zdefiniowana w Canvas i dlatego nie jest dostępna w innych pochodnych panelu.

ItemsControl zamawia podelementy zgodnie z kolejnością na liście. Pierwszy przedmiot na dole stosu i ostatni na górze. Po tym wszystkim, wszystko co musisz zrobić, to upewnić się, że wybrany element znajduje się na dole listy.

Najpierw utwórz interfejs dla zamówienia. W ten sposób:

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

Teraz zaimplementuj to w klasie, którą wyświetlasz.

Jeśli chcesz przynieść przedmiot z przodu, nadaj mu dużą liczbę i nadaj wszystkim innym niską liczbę.

Po lewej stronie jest faktyczne zamówienie. Dodaj coś takiego i jesteś ustawiony:

ItemsCont.ItemsSource = 
      ItemsCont.Items.OrderByDesc(t=>((IOrderable)t).theZOrder); 
+0

myślałem, że na początku, ale w porządku na elementy, które nakładają się na siebie, że wszyscy oni mają być dzieci z jednym dużym płótnie. Nie spodziewałbym się, że indeks z z jednego płótna wpłynie na indeks Z innego. Ale jeśli używam jednego dużego płótna, to i tak elementy te nie są jego bezpośrednimi potomkami. – Rich

+0

W rzeczywistości ZIndex działa dla innych typów Paneli. Śmiało i spróbuj tego. – ptoinson

15

W WPF jest własnością Panel.ZIndex, które można ustawić w wyzwalacz:

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

W Style dla ContentPresenter ustawiamy Panel.ZIndex do 99999 kiedy IsMouseOver jest. Musi on być pod numerem ContentPresenter, a nie Border, ponieważ s ContentPresenter s są elementami podrzędnymi panelu ItemsControl.

Niestety nie sądzę, ta właściwość stało się jeszcze Silverlight ...

+0

Tak ... Widziałem to również i używam ItemsControl jako mojego pojemnika, który pochodzi z panelu, ale rekwizyt nie jest dostępny w SL. Thx – Rich

+3

Dobra odpowiedź - to pomogło mi całkiem sporo. – Charlie

34

miałem do czynienia z tym.

Załóżmy, że obiekt ItemsControl z zestawem ItemTemplate jest ustawiony na niestandardową formant. W ramach tej kontroli robisz Canvas.SetZIndex (this, 99). To nie zadziała, ponieważ "to" nie jest bezpośrednim dzieckiem ItemPanel ItemsControl. ItemsControl tworzy ContentPresenter dla każdego elementu, upuszcza go do ItemsPanel i renderuje ItemTemplate w ContentPresenter.

Tak więc, jeśli chcesz zmienić ZIndex pod kontrolą, musisz znaleźć jego ContentPresenter i zmienić ZIndex na tym. Jednym ze sposobów jest ...

 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); 
+0

Oprócz błędów składniowych działa to. Próbowałem ustawić ZIndex z Silverlight Spy 3 (którego starałem się sprawdzić wszystko), ale to najwyraźniej nie ustawia ZIndex (ciągle powraca do 0). Znalezienie ContentPresentera przy użyciu tego pomocnika rozwiązało problem. –

+0

Legendarny, zrobił to sztuczka dla moich problemów z warstwami okien. –

+0

Pracowałem nad tym przez kilka dni przed znalezieniem tego postu. W przeciwieństwie do Barta, kod działał tak samo jak dla mnie. PS: Możesz zmienić funkcję FindVisualParent na normalną funkcję, jeśli nie chcesz używać metod rozszerzających, zmieniając prototyp funkcji na "public static T FindVisualParent (DependencyObject obj), gdzie T: DependencyObject" Następnie wywołujesz nowa metoda przez wywołanie ContentPresenter foo = this.FindVisualParent (this); –

2

Html działa w ten sam sposób. Wszystkie elementy listy muszą być rodzeństwem, jeśli chcesz je układać warstwami.

Wydłużyłem powyższy kod, aby się zatrzymał, jeśli znajdzie (na przykład) ItemsPresenter.Jeśli ContentPresenter nie wyświetli się tutaj, a ItemsPresenter, powróci do mojego oryginalnego kodu.

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; 
} 
3

Dla kontroli, która korzysta z siatki jak LayoutRoot można po prostu zrobić coś tak prostego jak w kontroli samego:

Canvas.SetZIndex(this, 999); 
1

ustawiony zindex swojego elementu w ten sposób

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

zIndex++; 

Canvas.SetZIndex(element, zIndex); 
  • Może musisz sprawdzić, czy zIndex jest równe int.MaxValue, a następnie zresetować "ZIndex".
  • ale prawie nigdy nie zdarza
3

Pierwszy znaleźć maksymalną zindex wszystkich jego elementów podrzędnych, a następnie ustawić nowy 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; 
} 

Następnie przypisz

Canvas.SetZIndex(child, MaxZIndex());