The grid in WPF currently has a grid system like this:
Cols
+ + + + +
| 0 | 1 | 2 | 3 |
+--+---|---|---|---|---
0 | | | | |
+--+---|---|---|---|--- Rows
1 | | | | |
+--+---|---|---|---|---
2 | | | | |
+--+---|---|---|---|---
Is there a way to make it behave like this:
Cols
+ + + + +
| 0 | 1 | 2 | 3 |
+--+---|---|---|---|---
2 | | | | |
+--+---|---|---|---|--- Rows
1 | | | | |
+--+---|---|---|---|---
0 | | | | |
+--+---|---|---|---|---
Ideally I would like the RowSpan to extend an item upwards instead of downwards.
Example:
My datasource stores a cube on the map as 0,0 with the intent of it being displayed on the bottom left corner. However the grid in WPF will put that cube on the top left. The other problem is the datasource gives me a 2x2 with the position of the bottom left "anchor" position with a width and height. The width and height are bound to ColSpan and RowSpan. The RowSpan is an issue because it will be expanded down the grid and not up.
You should be able to do this without having to create a custom or user control by using attached properties.
Here's a class that I think should be able to do what you want. Instead of binding the values of Grid.Row
and Grid.RowSpan
to your row and height, bind GridEx.RowFromBottom
and GridEx.RowSpanFromBottom
to them. The property change handlers for these properties will compute the new value of Grid.Row
based on the values of those properties and the number of rows in the grid.
One potential problem is that this may not update correctly if you're adding or subtracting rows from the grid at runtime.
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;
}
}
If you have any questions about what's going on here, feel free to ask.
You could achieve this by writing your own custom control. You could inherit from Grid
, or alternatively, use a UserControl
with a Grid
on it. Either way, you would provide the attached properties similarly to a Grid
, and you could then manipulate the values as you see fit, and then pass them on to the underlying Grid
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With