I am using a Grid as ItemsPanel for a list dynamically bound to an ItemsControl. The code below is working - with a remaining problem: I can’t find a way to dynamically initialize the ColumnDefinitions and RowDefinitions of the grid. As consequence all values are placed on top of each other.
<ItemsControl ItemsSource="{Binding Cells}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding RowIndex}"/>
<Setter Property="Grid.Column" Value="{Binding ColumnIndex}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Please be aware, that I am searching an answer according the MVVM pattern. Therefore sub classing and code behind are just workarounds, but no solutions.
You'll need some way to tell the Grid how many Rows/Columns it has. Perhaps as each Item loads you could check the value of RowIndex
and ColumnIndex
and add Rows/Columns to the Grid if needed.
As another alternative, perhaps you can expose RowCount
and ColumnCount
properties in your ViewModel that return the max RowIndex
and ColumnIndex
, and in the Grid's Loaded event add however many Columns/Rows you need.
I find it perfectly acceptable to use code-behind in MVVM IF the code is related to the UI only.
Another idea would be to arrange your items in your code-behind into a 2D grid before returning it to the View, and then bind that Grid to a DataGrid with AutoGenerateColumns=True
and the headers removed
Update
My current solution to this problem is to use a set of AttachedProperties
for a Grid
that allow you to bind RowCount
and ColumnCount
properties to a property on the ViewModel
You can find the code for my version of the attached properties on my blog here, and they can be used like this:
<ItemsPanelTemplate>
<Grid local:GridHelpers.RowCount="{Binding RowCount}"
local:GridHelpers.ColumnCount="{Binding ColumnCount}" />
</ItemsPanelTemplate>
Your grid has zero rows and columns so everything will be displayed on top of each other. Do something like below and it will work.
<ItemsControl ItemsSource="{Binding Cells}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding RowIndex}" />
<Setter Property="Grid.Column" Value="{Binding ColumnIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
i found this from here The ItemsControl
<ItemsControl ItemsSource="{Binding VehicleMakes}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="300" Height="100" Click="ButtonOption_Click" Tag="{Binding Name}">
<StackPanel Orientation="Vertical">
<Image
Initialized="Image_Initialized"
Tag="{Binding ResourseImageName}"
Width="116"
Height="30"
Margin="0,0,0,10" >
</Image>
<TextBlock Text="{Binding Name}" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
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