2012-09-18 42 views
6

Tôi có một trang WPF, với một Lưới trên đó.WPF: thu gọn GridSplitter?

Có ba hàng. Hàng 0 chứa GridView với Height="*". Hàng 1 chứa một GridSplitter với Height="auto". Hàng 2 chứa biểu mẫu chi tiết với Height="2*".

Đây là điều - tôi có nút được cho là sẽ chuyển đổi chế độ hiển thị của biểu mẫu chi tiết. Và điều đó hoạt động tốt. Ngoại trừ việc nó chỉ ẩn biểu mẫu trong Hàng 2, nó không mở rộng Lưới trong Hàng 0 để lấp đầy không gian. Những gì tôi muốn là cho các nút để chuyển đổi GridView trong Row 0 để mất tất cả các không gian, và sau đó để chuyển đổi trở lại nơi mà mọi thứ được.

Chơi xung quanh rõ ràng với Mức độ hiển thị của biểu mẫu bên trong hàng sẽ không thực hiện được những gì tôi muốn.

Nhưng tôi cần phải chơi gì?

Trả lời

2

tôi đã giới thiệu một phụ thuộc tài sản gắn liền để xử lý này trong ứng dụng của riêng tôi:

<Grid c:GridSplitterController.Watch="{Binding ElementName=GS_DetailsView}"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="1*" /> 
     <RowDefinition Height="200" /> 
    </Grid.RowDefinitions> 

    <SomeControl Grid.Row="0" /> 

    <GridSplitter x:Name="GS_DetailsView" 
        Height="4" 
        Grid.Row="1" 
        VerticalAlignment="Top" 
        HorizontalAlignment="Stretch" 
        ResizeBehavior="PreviousAndCurrent" 
        ResizeDirection="Rows" 
        Visibility="{Binding ShowDetails, 
             Converter={StaticResource boolvis}}" /> 

    <OtherControl Grid.Row="1" 
        Margin="0,4,0,0" 
        Visibility="{Binding ShowDetails, 
             Converter={StaticResource boolvis}}" /> 
</Grid> 

Đầu tiên xác định một tài sản gắn liền phù hợp trên một DependencyObject:

public static GridSplitter GetWatch(DependencyObject obj) 
{ 
    return (GridSplitter)obj.GetValue(WatchProperty); 
} 

public static void SetWatch(DependencyObject obj, GridSplitter value) 
{ 
    obj.SetValue(WatchProperty, value); 
} 

public static readonly DependencyProperty WatchProperty = 
    DependencyProperty.RegisterAttached(
     "Watch", 
     typeof(GridSplitter), 
     typeof(DependencyObject), 
     new UIPropertyMetadata(null, OnWatchChanged)); 

Sau đó lắng nghe IsVisibleChanged:

private static void OnWatchChanged(DependencyObject obj, 
    DependencyPropertyChangedEventArgs e) 
{ 
    if (obj == null) return; 
    if (obj is Grid) 
    { 
     var grid = obj as Grid; 
     var gs = e.NewValue as GridSplitter; 
     if (gs != null) 
     { 
      gs.IsVisibleChanged += (_sender, _e) => 
       { 
        UpdateGrid(
         grid, 
         (GridSplitter)_sender, 
         (bool)_e.NewValue, 
         (bool)_e.OldValue); 
       }; 
     } 
    } 
} 

Khi bạn đang xem thay đổi e, bạn cần phải lưu hoặc khôi phục lại GridLength giá trị từ hàng hoặc cột mà bạn đang theo dõi (cho ngắn gọn tôi chỉ bao gồm Rows):

// Given: static Dictionary<DependencyObject, GridLength> oldValues; 
private static void UpdateGrid(Grid grid, GridSplitter gridSplitter, bool newValue, bool oldValue) 
{ 
    if (newValue) 
    { 
     // We're visible again 
     switch (gridSplitter.ResizeDirection) 
     { 
     case GridResizeDirection.Columns: 
      break; 
     case GridResizeDirection.Rows: 
      int ridx = (int)gridSplitter.GetValue(Grid.RowProperty); 
      var prev = grid.RowDefinitions.ElementAt(GetPrevious(gridSplitter, ridx)); 
      var curr = grid.RowDefinitions.ElementAt(GetNext(gridSplitter, ridx)); 
      if (oldValues.ContainsKey(prev) && oldValues.ContainsKey(curr)) 
      { 
       prev.Height = oldValues[prev]; 
       curr.Height = oldValues[curr]; 
      } 

      break; 
     } 
    } 
    else 
    { 
     // We're being hidden 
     switch (gridSplitter.ResizeDirection) 
     { 
     case GridResizeDirection.Columns: 
      break; 
     case GridResizeDirection.Rows: 
      int ridx = (int)gridSplitter.GetValue(Grid.RowProperty); 
      var prev = grid.RowDefinitions.ElementAt(GetPrevious(gridSplitter, ridx)); 
      var curr = grid.RowDefinitions.ElementAt(GetNext(gridSplitter, ridx)); 
      switch (gridSplitter.ResizeBehavior) 
      { 
       // Naively assumes only one type of collapsing! 
       case GridResizeBehavior.PreviousAndCurrent: 
        oldValues[prev] = prev.Height; 
        prev.Height = new GridLength(1.0, GridUnitType.Star); 

        oldValues[curr] = curr.Height; 
        curr.Height = new GridLength(0.0); 
        break; 
      } 
      break; 
     } 
    } 
} 

Tất cả những gì còn lại là một việc thực hiện phù hợp của GetPreviousGetNext :

private static int GetPrevious(GridSplitter gridSplitter, int index) 
{ 
    switch (gridSplitter.ResizeBehavior) 
    { 
     case GridResizeBehavior.PreviousAndNext: 
     case GridResizeBehavior.PreviousAndCurrent: 
      return index - 1; 
     case GridResizeBehavior.CurrentAndNext: 
      return index; 
     case GridResizeBehavior.BasedOnAlignment: 
     default: 
      throw new NotSupportedException(); 
    } 
} 

private static int GetNext(GridSplitter gridSplitter, int index) 
{ 
    switch (gridSplitter.ResizeBehavior) 
    { 
     case GridResizeBehavior.PreviousAndCurrent: 
      return index; 
     case GridResizeBehavior.PreviousAndNext: 
     case GridResizeBehavior.CurrentAndNext: 
      return index + 1; 
     case GridResizeBehavior.BasedOnAlignment: 
     default: 
      throw new NotSupportedException(); 
    } 
} 
2

này GridExpander điều khiển mà được thừa hưởng hình thức GridSpliter có thể đến công việc bạn đang tìm kiếm. Tín dụng đi đến Shemesh để viết phiên bản Silverlight gốc mà tôi đã thích nghi cho việc sử dụng của riêng tôi trong WPF. Tôi thấy mình muốn chức năng này hầu như ở khắp mọi nơi tôi cố gắng sử dụng GridSplitter để nó có thể khá tiện dụng.

+1

Phải là một câu trả lời được chấp nhận thực sự. Công việc tốt đẹp! –

4

Giả sử tôi có bố trí này XAML:

<Grid Name="MyGrid"> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 
     <MyControl1 ... Grid.Row="0" /> 
     <GridSplitter Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" ShowsPreview="True" Height="5" /> 
     <MyControl2 ... Grid.Row="2" /> 
    </Grid> 

Sau đó, tôi có thể giấu sự kiểm soát thứ hai (sụp đổ splitter xuống) với mã này (tương đương với thiết Height="0" trong XAML):

MyGrid.RowDefinitions[2].Height = new GridLength(0); 

Và không nén nó với mã này (tương đương với thiết lập Height="1*" trong XAML, là mặc định cho một RowDefinition):

MyGrid.RowDefinitions[2].Height = new GridLength(1, GridUnitType.Star); 

Đây là những gì bộ tách không được trải dưới khi người dùng di chuyển nó.

Các vấn đề liên quan