2012-04-05 18 views
6

La rejilla en WPF tiene actualmente un sistema de red de esta manera:Cambio cuadrícula de coordenadas Sistema

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

¿Hay una manera de hacer que se comporte de esta manera:

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

Idealmente me gustaría que el RowSpan para extender un elemento hacia arriba en lugar de hacia abajo.

Ejemplo:

Mis origen de datos almacena un cubo en el mapa como 0,0 con la intención de que sea mostrarán en la esquina inferior izquierda. Sin embargo, la cuadrícula en WPF pondrá ese cubo en la parte superior izquierda. El otro problema es que la fuente de datos me da un 2x2 con la posición de la posición "ancla" inferior izquierda con ancho y alto. El ancho y la altura están vinculados a ColSpan y RowSpan. El RowSpan es un problema porque se expandirá hacia abajo en la cuadrícula y no hacia arriba.

+1

¿Podría dar un ejemplo que ilustra por qué lo necesita? – sll

+0

Agregué un ejemplo – Robert

+1

diagrama genial :) – Aftnix

Respuesta

1

Usted debe ser capaz de hacer esto sin tener que crear una costumbre o control de usuario mediante el uso de las propiedades asociadas.

Aquí es una clase que creo que debería ser capaz de hacer lo que quiera. En lugar de vincular los valores de Grid.Row y Grid.RowSpan a su fila y altura, vincule GridEx.RowFromBottom y GridEx.RowSpanFromBottom. Los manejadores de cambio de propiedad para estas propiedades calcularán el nuevo valor de Grid.Row según los valores de esas propiedades y el número de filas en la grilla.

Un problema potencial es que esto no puede actualizar correctamente si va a añadir o restar filas de la cuadrícula en tiempo de ejecución.

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

Si usted tiene alguna pregunta acerca de lo que está pasando aquí, no dude en preguntar.

1

Puede lograr esto escribiendo su propio control personalizado. Puede heredar de Grid, o alternativamente, usar un UserControl con un Grid en él. De cualquier manera, proporcionaría las propiedades adjuntas de manera similar a Grid, y luego podría manipular los valores como mejor le parezca, y luego pasarlos al Grid subyacente.

+0

¿Podría ser más específico sobre la creación de un control personalizado que herede de Grid? Por ejemplo, qué métodos anular, es bastante confuso. – Robert

+0

No creo que deba ser un gran problema. Debería investigar cómo implementar las propiedades adjuntas, ya que así es como los paneles realizan el diseño. Si se encuentra con problemas específicos, no dude en hacer otra pregunta en SO. –

1

¿Está el Grid donde se está mostrando los cubos de un tamaño fijo? Si es así, usted podría considerar escribir un modelo de vista que convierte/invierte el modelo coordina con el fin de trabajar en la vista, es decir, el cubo tendría que tener el valor (0,0) y el modelo de vista expondría a ese valor como (0,2).

Simplemente una idea que puede ser más fácil que rodar su propio control.

1

Pruebe este convertidor. XAML parecer un poco complicado, pero no se requieren ViewModel (s) o de control de usuario (s):

convertidor para voltear filas:

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. La primera cuadrícula es original, el segundo se da la vuelta:

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

Por desgracia, es incapaz de pasar recuento de filas como un tercer valor, porque RowDefinitionCollection no notifica acerca de los cambios. Es por eso que agregué RowCount como propiedad de convertidor.

0

Se puede convertir el formato de fila de la siguiente manera inversa:

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

Esto revertirá la fila.

Cuestiones relacionadas