I try to use a grid as ItemsPanelTemplate
in an ItemsControl
. The column and row properties are bound. Unfortunately all items are overlapping and not displayed correctly.
My view:
<ItemsControl BorderBrush="Black" BorderThickness="5" Margin="5" ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Button BorderBrush="Red" BorderThickness="2" Grid.Row="{Binding YIndex}" Grid.Column="{Binding XIndex}" Padding="0" Background="White">
<StackPanel Width="200" Height="100" Background="{Binding Color}">
<TextBlock Margin="10" FontSize="20" FontWeight="Bold" TextAlignment="Center" Text="{Binding Name}"></TextBlock>
<TextBlock Margin="10" FontSize="20" FontWeight="Bold" TextAlignment="Center" Text="{Binding Price}"></TextBlock>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
View model:
public class GridViewModel
{
public ObservableCollection<GridItemViewModel> Items { get; set; } = new();
public GridViewModel()
{
// dummy data
for (uint i = 0; i < 5; i++)
{
for (uint j = 0; j < 5; j++)
{
Items.Add(new GridItemViewModel()
{
XIndex = i,
YIndex = j,
Name = $"X: {i} Y: {j}",
Price = 12.32m,
Color = "LightBlue"
});
}
}
}
}
Seems like the grid columns and rows are not set correctly. What am I missing?
If I just use a wrap panel as PanelTemplate
without bound indices, it works fine, but I want to use explicitly a grid.
The comment of @ASh was a good start. Instead of using the WPF ItemContainerStyle, the property setter can be used in Avalonia Grids as follows:
<ItemsControl.Styles>
<Style x:DataType="md:Element" Selector="ItemsControl > ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Row}" />
<Setter Property="Grid.Column" Value="{Binding Column}" />
</Style>
</ItemsControl.Styles>
Based on the linked blog entry, I have created a respective behavior that allows the binding of the Grid.RowDefintions / Grid.ColumnDefintions for MVVM controls.
public static class GridDefinitionBehavior
{
#region Public Fields
/// <summary>
/// Adds the specified number of Columns to ColumnDefinitions.
/// Default Width is Auto
/// </summary>
public static readonly StyledProperty<int> ColumnCountProperty = AvaloniaProperty.Register<Grid, int>(
name: "ColumnCount",
defaultValue: -1);
/// <summary>
/// Adds the specified number of Rows to RowDefinitions.
/// Default Height is Auto
/// </summary>
public static readonly StyledProperty<int> RowCountProperty = AvaloniaProperty.Register<Grid, int>(
name: "RowCount",
defaultValue: -1);
/// <summary>
/// Makes the specified Column's Width equal to Star.
/// Can set on multiple Columns
/// </summary>
public static readonly StyledProperty<string> StarColumnsProperty = AvaloniaProperty.Register<Grid, string>(
name: "StarColumns",
defaultValue: string.Empty);
/// <summary>
/// Makes the specified Row's Height equal to Star.
/// Can set on multiple Rows
/// </summary>
public static readonly StyledProperty<string> StarRowsProperty = AvaloniaProperty.Register<Grid, string>(
name: "StarRows",
defaultValue: string.Empty);
#endregion Public Fields
#region Public Constructors
static GridDefinitionBehavior()
{
ColumnCountProperty.Changed.Subscribe(e => ColumnCountChanged(
obj: e.Sender,
args: e));
RowCountProperty.Changed.Subscribe(e => RowCountChanged(
obj: e.Sender,
args: e));
StarColumnsProperty.Changed.Subscribe(e => StarColumnsChanged(
obj: e.Sender,
args: e));
StarRowsProperty.Changed.Subscribe(e => StarRowsChanged(
obj: e.Sender,
args: e));
}
#endregion Public Constructors
#region Public Methods
public static void ColumnCountChanged(AvaloniaObject obj, AvaloniaPropertyChangedEventArgs args)
{
if (obj is Grid grid
&& (int)args.NewValue >= 0)
{
grid.ColumnDefinitions.Clear();
for (var index = 0; index < (int)args.NewValue; index++)
{
var definition = new ColumnDefinition()
{
Width = GridLength.Auto
};
grid.ColumnDefinitions.Add(definition);
}
SetStarColumns(grid);
}
}
public static int GetColumnCount(AvaloniaObject obj)
{
return (int)obj.GetValue(ColumnCountProperty);
}
public static int GetRowCount(AvaloniaObject obj)
{
return (int)obj.GetValue(RowCountProperty);
}
public static string GetStarColumns(AvaloniaObject obj)
{
return (string)obj.GetValue(StarColumnsProperty);
}
public static string GetStarRows(AvaloniaObject obj)
{
return (string)obj.GetValue(StarRowsProperty);
}
public static void RowCountChanged(AvaloniaObject obj, AvaloniaPropertyChangedEventArgs args)
{
if (obj is Grid grid
&& (int)args.NewValue >= 0)
{
grid.RowDefinitions.Clear();
for (var index = 0; index < (int)args.NewValue; index++)
{
var definition = new RowDefinition()
{
Height = GridLength.Auto
};
grid.RowDefinitions.Add(definition);
}
SetStarRows(grid);
}
}
public static void SetColumnCount(AvaloniaObject obj, int value)
{
obj.SetValue(ColumnCountProperty, value);
}
public static void SetRowCount(AvaloniaObject obj, int value)
{
obj.SetValue(RowCountProperty, value);
}
public static void SetStarColumns(AvaloniaObject obj, string value)
{
obj.SetValue(StarColumnsProperty, value);
}
public static void SetStarRows(AvaloniaObject obj, string value)
{
obj.SetValue(StarRowsProperty, value);
}
public static void StarColumnsChanged(AvaloniaObject obj, AvaloniaPropertyChangedEventArgs args)
{
if (obj is Grid grid
&& !string.IsNullOrEmpty(args.NewValue.ToString()))
{
SetStarColumns(grid);
}
}
public static void StarRowsChanged(AvaloniaObject obj, AvaloniaPropertyChangedEventArgs args)
{
if (obj is Grid grid
&& !string.IsNullOrEmpty(args.NewValue.ToString()))
{
SetStarRows(grid);
}
}
#endregion Public Methods
#region Private Methods
private static void SetStarColumns(Grid grid)
{
var starColumns = GetStarColumns(grid);
if (!string.IsNullOrWhiteSpace(starColumns))
{
var regex = new Regex(starColumns);
for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
{
if (regex.IsMatch(i.ToString()))
{
grid.ColumnDefinitions[i].Width = new GridLength(
value: 1,
type: GridUnitType.Star);
}
}
}
}
private static void SetStarRows(Grid grid)
{
var starRows = GetStarRows(grid);
if (!string.IsNullOrWhiteSpace(starRows))
{
var regex = new Regex(starRows);
for (int i = 0; i < grid.RowDefinitions.Count; i++)
{
if (regex.IsMatch(i.ToString()))
{
grid.RowDefinitions[i].Height = new GridLength(
value: 1,
type: GridUnitType.Star);
}
}
}
}
#endregion Private Methods
}
The respective repository can be found here.