2012-04-05 89 views
6

在WPF電網目前已形成網格系統是這樣的:更改網格座標系統

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

有沒有辦法讓它這樣的表現:

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

理想我想的行跨度向上而不是向下延伸物品。

例子:

我的數據源存儲地圖與0,0與它的意圖在立方體上被顯示在左下角。但是WPF中的網格會將該立方體置於左上角。另一個問題是數據源爲我提供了一個2x2的位置,左下角的「錨」位置的寬度和高度。寬度和高度與ColSpan和RowSpan綁定。 RowSpan是一個問題,因爲它會向下擴展,而不是向上。

+1

你能舉一個例子說明你爲什麼需要這個嗎? – sll 2012-04-05 20:35:45

+0

我添加了一個例子 – Robert 2012-04-05 21:54:27

+1

酷圖:) – Aftnix 2012-04-25 20:09:32

回答

1

您應該可以做到這一點,而無需使用附加屬性創建自定義或用戶控件。

這是我認爲應該能夠做你想做的一類。代替將Grid.RowGrid.RowSpan的值綁定到您的行和高度,將GridEx.RowFromBottomGridEx.RowSpanFromBottom綁定到它們。這些屬性的屬性更改處理程序將根據這些屬性的值和網格中的行數計算新值Grid.Row

一個潛在的問題是,如果您在運行時從網格中添加或減去行,這可能無法正確更新。

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

如果您對這裏發生的事情有任何疑問,請隨時詢問。

1

您可以通過編寫自己的自定義控件來實現此目的。您可以從Grid繼承,或者,也可以使用UserControlGrid。無論哪種方式,您都會提供附加的屬性,類似於Grid,然後您可以根據需要操作這些值,然後將它們傳遞給底層的Grid

+0

你能更具體地瞭解如何創建一個從網格繼承的自定義控件嗎?例如重寫什麼方法,這相當混亂。 – Robert 2012-04-06 16:35:45

+0

我不認爲這應該是一個大問題。您應該研究如何實現附加屬性,因爲這是面板如何執行佈局。如果遇到特定問題,請隨時就SO提出另一個問題。 – 2012-04-07 02:55:03

1

Grid您正在顯示立方體的大小是否固定?如果是這樣,你可以考慮編寫一個視圖模型來轉換/取消模型座標以便在視圖中工作,即該立方體的值將爲(0,0),ViewModel會將該值顯示爲(0,2)

只是一個想法,可能比滾動自己的控制更容易。

1

試試這個轉換器。 XAML看起來有點複雜,但沒有視圖模型(S)或用戶控件(S)是必需的:

轉換器翻轉行:

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。第一個網格是原創,二是翻轉:

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

不幸的是,它是無法通過行數作爲第三值,因爲RowDefinitionCollection不會通知用戶更改。這就是爲什麼我添加RowCount作爲轉換器的屬性。

0

您可以轉換行扭轉如下格式:

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

這將恢復該行。