2009-03-10 31 views
36

Tất cả tài liệu và ví dụ tôi đang tìm kiếm trực tuyến để thiết lập Z-Index mang phần tử chuyển tiếp trong Silverlight đang sử dụng phần tử Canvas làm vùng chứa.Đưa phần tử tiến lên (Z Index) trong Silverlight/WPF

Các mục của tôi là các phần tử Biên giới bên trong một vùng chứa ItemsControl trong DataTemplate. Tôi đang sử dụng sự kiện MouseEnter và MouseLeave để kích hoạt hoạt ảnh trên ScaleTransform.ScaleX và ScaleTransform.ScaleY để chúng phát triển khi được di chuột. Khi chúng được thay đổi kích thước và chiếm không gian giống như các mục khác trong (các) vùng chứa, các mục được thêm gần đây nhất là chồng chéo các mục cũ hơn (trái ngược với mục hiện đang thay đổi kích cỡ). Có cách nào SẠCH để đưa mục hiện tại về phía trước trong mã mà tôi kích hoạt hoạt ảnh của tôi sao cho chúng trùng lặp tất cả các mục khác khi chúng được thay đổi kích cỡ?

Trả lời

2

Đầu tiên, thuộc tính đính kèm Zindex được xác định trong Canvas và do đó không có sẵn trong các dẫn xuất khác của Bảng điều khiển.

ItemsControl yêu cầu các phần tử con theo thứ tự của danh sách. Mục đầu tiên ở cuối ngăn xếp và mục cuối cùng ở trên cùng. Với điều đó, tất cả những gì bạn phải làm là đảm bảo mục đã chọn nằm ở cuối danh sách.

Trước tiên hãy tạo giao diện cho thứ tự. Như thế này:

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

Bây giờ hãy thực hiện điều này trong lớp bạn đang hiển thị.

Khi bạn muốn mang vật phẩm lên phía trước, hãy mang nó đến số cao và cho mọi người một số thấp.

Al còn lại là thứ tự thực tế. Thêm một cái gì đó như thế này và bạn đang thiết lập:

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

Tôi nghĩ về điều đó lúc đầu, nhưng để cho các yếu tố để chồng lên nhau, họ muốn tất cả phải được làm con của một canvas lớn. Tôi sẽ không mong đợi một chỉ số z trong một canvas để có ảnh hưởng đến chỉ số z của chỉ số khác. Nhưng nếu tôi sử dụng một canvas lớn, các phần tử không phải là con của nó một cách trực tiếp – Rich

+0

Thực ra, ZIndex hoạt động với các loại Panel khác. Đi trước và thử nó. – ptoinson

15

Trong WPF có là Panel.ZIndex tài sản mà bạn có thể thiết lập trong một 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> 

Trong Style cho ContentPresenter chúng tôi đặt Panel.ZIndex-99.999 khi IsMouseOvertrue. Nó phải nằm trên ContentPresenter và không phải là Border vì số ContentPresenter là con của bảng điều khiển của ItemsControl.

Rất tiếc, tôi không nghĩ rằng thuộc tính này đã chuyển sang Silverlight ...

+0

Vâng ... Tôi đã thấy điều đó, và tôi đang sử dụng ItemsControl như container của tôi xuất phát từ Panel, nhưng prop không có sẵn trong SL. Thx – Rich

+3

Câu trả lời hay-- điều này đã giúp tôi khá nhiều. – Charlie

34

Tôi phải giải quyết vấn đề này.

Giả sử bạn có một ItemsControl với một ItemTemplate được đặt thành một thể hiện của một điều khiển tùy chỉnh. Trong điều khiển đó bạn làm Canvas.SetZIndex (điều này, 99). Nó sẽ không hoạt động, bởi vì "điều này" không phải là con ngay lập tức của ItemsControl của ItemsControl. ItemsControl tạo ra một ContentPresenter cho mỗi mục, thả nó vào trong ItemsPanel, và hiển thị ItemTemplate bên trong ContentPresenter.

Vì vậy, nếu bạn muốn thay đổi ZIndex trong tầm kiểm soát của mình, bạn phải tìm ContentPresenter của nó và thay đổi ZIndex trên đó. Một cách là ...

 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

Ngoài các lỗi cú pháp, công trình này còn hoạt động. Tôi đã thử thiết lập ZIndex từ Silverlight Spy 3 (mà tôi đã cố gắng để kiểm tra tất cả điều này), nhưng điều đó dường như không thiết lập ZIndex (nó tiếp tục quay trở lại 0). Việc tìm kiếm các ContentPresenter bằng cách sử dụng helper này đã làm các trick. –

+0

Huyền thoại, điều này đã làm các trick cho các vấn đề phân lớp cửa sổ của tôi. –

+0

Làm việc này trong nhiều ngày trước khi tìm bài đăng này. Không giống như Bart, mã đã làm việc khá nhiều như đối với tôi. PS: Bạn có thể thay đổi hàm FindVisualParent thành hàm bình thường, nếu bạn không muốn sử dụng các phương thức mở rộng, bằng cách thay đổi nguyên mẫu hàm thành "public static T FindVisualParent (DependencyObject obj) trong đó T: DependencyObject", bạn gọi phương thức mới bằng cách gọi ContentPresenter foo = this.FindVisualParent (điều này); –

2

Html hoạt động theo cùng một cách. Tất cả các mục trong danh sách phải là anh chị em nếu bạn muốn đặt chúng trong các lớp.

Tôi đã mở rộng mã ở trên để nó dừng lại nếu nó tìm thấy (ví dụ) một ItemsPresenter.Nếu ContentPresenter không hiển thị chính nó giữa đây và các ItemsPresenter, sau đó rơi trở lại trên mã ban đầu của tôi.

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

Đối với một điều khiển có sử dụng lưới như LayoutRoot bạn chỉ có thể làm điều gì đó đơn giản như vậy trong vòng một điều khiển bản thân:

Canvas.SetZIndex(this, 999); 
1

thiết ZIndex của nguyên tố của bạn theo cách này

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

zIndex++; 

Canvas.SetZIndex(element, zIndex); 
  • có thể bạn cần kiểm tra xem zIndex có bằng int.MaxValue sau đó đặt lại "ZIndex" không.
  • nhưng điều này gần như không bao giờ xảy ra
3

Đầu tiên tìm ra tối đa ZIndex của tất cả các phần tử con của nó và sau đó thiết lập các ZIndex mới.

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

Sau đó gán

Canvas.SetZIndex(child, MaxZIndex()); 
Các vấn đề liên quan