2012-04-05 34 views
6

Lưới trong WPF hiện đang có một hệ thống lưới điện như thế này:Thay đổi Lưới Hệ tọa độ

Cols 
    + + + + + 
    | 0 | 1 | 2 | 3 | 
+--+---|---|---|---|--- 
0 | | | | | 
+--+---|---|---|---|--- Rows 
1 | | | | | 
+--+---|---|---|---|--- 
2 | | | | | 
+--+---|---|---|---|--- 

Có cách nào để làm cho nó cư xử như thế này:

Cols 
    + + + + + 
    | 0 | 1 | 2 | 3 | 
+--+---|---|---|---|--- 
2 | | | | | 
+--+---|---|---|---|--- Rows 
1 | | | | | 
+--+---|---|---|---|--- 
0 | | | | | 
+--+---|---|---|---|--- 

Lý tưởng nhất là tôi muốn các rowspan để mở rộng một mục lên trên thay vì xuống dưới.

Ví dụ:

cửa hàng My nguồn dữ liệu một khối lập phương trên bản đồ dưới 0,0 với mục đích của nó được hiển thị ở góc dưới bên trái. Tuy nhiên, lưới trong WPF sẽ đặt khối lập phương đó lên trên cùng bên trái. Các vấn đề khác là nguồn dữ liệu cho tôi một 2x2 với vị trí của vị trí dưới cùng bên trái "neo" với chiều rộng và chiều cao. Chiều rộng và chiều cao được ràng buộc với ColSpan và RowSpan. RowSpan là một vấn đề bởi vì nó sẽ được mở rộng xuống lưới và không lên.

+1

Bạn có thể đưa ra ví dụ minh họa tại sao bạn cần điều đó không? – sll

+0

Tôi đã thêm một ví dụ – Robert

+1

biểu đồ nguội :) – Aftnix

Trả lời

1

Bạn sẽ có thể thực hiện việc này mà không phải tạo điều khiển tùy chỉnh hoặc người dùng bằng cách sử dụng các thuộc tính được đính kèm.

Đây là một lớp học mà tôi nghĩ rằng sẽ có thể làm những gì bạn muốn. Thay vì ràng buộc các giá trị của Grid.RowGrid.RowSpan vào hàng và chiều cao của bạn, hãy liên kết GridEx.RowFromBottomGridEx.RowSpanFromBottom với chúng. Trình xử lý thay đổi thuộc tính cho các thuộc tính này sẽ tính toán giá trị mới của Grid.Row dựa trên các giá trị của các thuộc tính đó và số lượng hàng trong lưới.

Một vấn đề tiềm năng là điều này có thể không cập nhật chính xác nếu bạn đang thêm hoặc trừ các hàng từ lưới khi chạy.

public static class GridEx 
{ 
    public static readonly DependencyProperty RowFromBottomProperty = DependencyProperty.RegisterAttached("RowFromBottom", typeof(int?), typeof(GridEx), new FrameworkPropertyMetadata(default(int?), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsParentArrange | FrameworkPropertyMetadataOptions.AffectsParentMeasure, OnRowFromBottomChanged)); 
    public static readonly DependencyProperty RowSpanFromBottomProperty = DependencyProperty.RegisterAttached("RowSpanFromBottom", typeof(int?), typeof(GridEx), new FrameworkPropertyMetadata(default(int?), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsParentArrange | FrameworkPropertyMetadataOptions.AffectsParentMeasure, OnRowSpanFromBottomChanged)); 

    private static void OnRowFromBottomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var grid = GetContainingGrid(d); 
     int? rowFromBottom = (int?) e.NewValue; 
     int? rowSpanFromBottom = GetRowSpanFromBottom(d); 
     if (rowFromBottom == null || rowSpanFromBottom == null) return; 
     int rows = grid.RowDefinitions.Count; 
     int row = Math.Max(0, Math.Min(rows, rows - rowFromBottom.Value - rowSpanFromBottom.Value)); 
     Grid.SetRow((UIElement) d, row); 
    } 

    private static void OnRowSpanFromBottomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var grid = GetContainingGrid(d); 
     int? rowFromBottom = GetRowFromBottom(d); 
     int? rowSpanFromBottom = (int?)e.NewValue; 
     if (rowFromBottom == null || rowSpanFromBottom == null) return; 
     int rows = grid.RowDefinitions.Count; 
     int row = Math.Max(0, Math.Min(rows, rows - rowFromBottom.Value - rowSpanFromBottom.Value)); 
     Grid.SetRow((UIElement)d, row); 
     Grid.SetRowSpan((UIElement)d, rowSpanFromBottom.Value); 
    } 

    public static int? GetRowFromBottom(DependencyObject obj) 
    { 
     return (int?) obj.GetValue(RowFromBottomProperty); 
    } 

    public static void SetRowFromBottom(DependencyObject obj, int? value) 
    { 
     obj.SetValue(RowFromBottomProperty, value); 
    } 

    public static int? GetRowSpanFromBottom(DependencyObject obj) 
    { 
     return (int?)obj.GetValue(RowSpanFromBottomProperty); 
    } 

    public static void SetRowSpanFromBottom(DependencyObject obj, int? value) 
    { 
     obj.SetValue(RowSpanFromBottomProperty, value); 
    } 

    private static Grid GetContainingGrid(DependencyObject element) 
    { 
     Grid grid = null; 
     while (grid == null && element != null) 
     { 
      element = LogicalTreeHelper.GetParent(element); 
      grid = element as Grid; 
     } 
     return grid; 
    } 
} 

Nếu bạn có bất kỳ câu hỏi nào về những gì đang diễn ra ở đây, vui lòng hỏi.

1

Bạn có thể đạt được điều này bằng cách viết điều khiển tùy chỉnh của riêng bạn. Bạn có thể kế thừa từ Grid hoặc cách khác, sử dụng một số UserControl với số Grid trên đó. Dù bằng cách nào, bạn sẽ cung cấp các thuộc tính đính kèm tương tự như một Grid, và sau đó bạn có thể thao tác các giá trị như bạn thấy phù hợp, và sau đó chuyển chúng vào bên dưới Grid.

+0

Bạn có thể cụ thể hơn về việc tạo một điều khiển tùy chỉnh kế thừa từ Lưới không? Ví dụ như những phương pháp để ghi đè lên, nó khá khó hiểu. – Robert

+0

Tôi không nghĩ đó là một vấn đề lớn. Bạn nên nghiên cứu cách triển khai thuộc tính đính kèm, vì đó là cách Panels thực hiện bố cục. Nếu bạn gặp phải các vấn đề cụ thể, vui lòng đặt câu hỏi khác về SO. –

1

Có phải là Grid nơi bạn đang hiển thị hình khối có kích thước cố định không? Nếu vậy, bạn có thể xem xét viết một ViewModel chuyển đổi/đảo ngược tọa độ mô hình để làm việc trong chế độ xem, nghĩa là khối lập phương sẽ có giá trị (0,0) và ViewModel sẽ hiển thị giá trị đó là (0,2).

Chỉ là một ý tưởng có thể dễ dàng hơn so với việc điều khiển riêng của bạn.

1

Thử công cụ chuyển đổi này. XAML tìm một chút phức tạp, nhưng không ViewModel (s) hoặc UserControl (s) là bắt buộc:

Converter để lật hàng:

public class UpsideDownRowConverter : IMultiValueConverter 
{ 
    public int RowCount 
    { 
     get; 
     set; 
    } 

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values.Length == 2 && values[0] is int && values[1] is int) 
     { 
      var row = (int)values[0]; 
      var rowSpan = (int)values[1]; 

      row = this.RowCount - row - rowSpan; 

      return row; 
     } 

     return DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

XAML. Lưới đầu tiên là bản gốc, thứ hai được lật:

<Window.Resources> 
    <local:UpsideDownRowConverter x:Key="UpsideDownRowConverter" 
            RowCount="3"/> 
</Window.Resources> 
<UniformGrid Rows="2"> 
    <Grid Name="Original" 
      Margin="0,0,0,10"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Rectangle Fill="Green" 
        Grid.Column="0" 
        Grid.Row="2"/> 
     <Rectangle Fill="Red" 
        Grid.Column="1" 
        Grid.Row="1"/> 
     <Rectangle Fill="Blue" 
        Grid.Column="2" 
        Grid.RowSpan="3"/> 
     <Rectangle Fill="Yellow" 
        Grid.Column="3" 
        Grid.RowSpan="2"/> 
    </Grid> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Rectangle Fill="Green" 
        Grid.Column="0"> 
      <Grid.Row> 
       <MultiBinding Converter="{StaticResource UpsideDownRowConverter}"> 
        <Binding Path="Children[0].(Grid.Row)" 
           ElementName="Original"/> 
        <Binding Path="(Grid.RowSpan)" 
           RelativeSource="{RelativeSource Self}"/> 
       </MultiBinding> 
      </Grid.Row> 
     </Rectangle> 
     <Rectangle Fill="Red" 
        Grid.Column="1"> 
      <Grid.Row> 
       <MultiBinding Converter="{StaticResource UpsideDownRowConverter}"> 
        <Binding Path="Children[1].(Grid.Row)" 
           ElementName="Original"/> 
        <Binding Path="(Grid.RowSpan)" 
           RelativeSource="{RelativeSource Self}"/> 
       </MultiBinding> 
      </Grid.Row> 
     </Rectangle> 
     <Rectangle Fill="Blue" 
        Grid.Column="2" 
        Grid.RowSpan="3"> 
      <Grid.Row> 
       <MultiBinding Converter="{StaticResource UpsideDownRowConverter}"> 
        <Binding Path="Children[2].(Grid.Row)" 
           ElementName="Original"/> 
        <Binding Path="(Grid.RowSpan)" 
           RelativeSource="{RelativeSource Self}"/> 
       </MultiBinding> 
      </Grid.Row> 
     </Rectangle> 
     <Rectangle Fill="Yellow" 
        Grid.Column="3" 
        Grid.RowSpan="2"> 
      <Grid.Row> 
       <MultiBinding Converter="{StaticResource UpsideDownRowConverter}"> 
        <Binding Path="Children[3].(Grid.Row)" 
           ElementName="Original"/> 
        <Binding Path="(Grid.RowSpan)" 
           RelativeSource="{RelativeSource Self}"/> 
       </MultiBinding> 
      </Grid.Row> 
     </Rectangle> 
    </Grid> 
</UniformGrid> 

Thật không may, nó không thể chuyển số hàng là giá trị thứ ba, vì RowDefinitionCollection không thông báo về thay đổi. Đó là lý do tại sao tôi đã thêm RowCount làm tài sản của trình biến đổi.

0

Bạn có thể chuyển đổi hàng để đảo ngược định dạng như dưới đây:

private void ReverseRow(Grid grd) 
    { 
     int totalRows = grd.RowDefinitions.Count-1; 
     foreach (UIElement ctl in grd.Children) 
     { 
      int currentRowIndex = Grid.GetRow(ctl); 
      Grid.SetRow(ctl, totalRows - currentRowIndex); 
     } 
    } 

này sẽ hoàn nguyên liên tiếp.

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