I have a collection that I wish to bind to a WPF grid.
The problem I'm facing is that the number of columns is dynamic and is dependent on a collection. Here is a simple mock up:
public interface IRows
{
string Message{get;}
IColumns[] Columns{get;}
}
public interface IColumns
{
string Header {get;}
AcknowledgementState AcknowledgementState{get;}
}
public interface IViewModel
{
ObservableCollection<IRows> Rows {get;}
}
I want my view to bind to the the Rows collection, which contains a collection of Columns.
My Columns collection contains an enum which should be represented by an image (1 of 3 possibilities). It also contains a Message property which should only be displayed in one column (static and is just some text information). It also contains a Header string which should be displayed as a header for that column.
Note that the number of columns is variable (at the moment the headers are set to Acknowledge but this will change to represent dynamic data).
Update: This is after implementing suggestions from Rachel
<ItemsControl
ItemsSource="{Binding Items, Converter={StaticResource PresentationConverter}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid ShowGridLines="true"
local:GridHelpers.RowCount="{Binding RowCount}"
local:GridHelpers.ColumnCount="{Binding ColumnCount}" />
</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>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type UI:MessageEntity}">
<TextBox Text="{Binding Message}"></TextBox>
</DataTemplate>
<DataTemplate DataType="{x:Type UI:StateEntity}">
<TextBox Text="{Binding State}"></TextBox>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This almost gives me what I want now. I'm only stuck with what I should do for the headers. Any suggestions are welcome.
You can use nested ItemsControls
for this
Here's a basic example:
<!-- Bind Rows using the default StackPanel for the ItemsPanel -->
<ItemsControl ItemsSource="{Binding Rows}">
<!-- Set the Template for each row to a TextBlock and another ItemsControl -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- Need to set Width of name TextBlock so items line up correctly -->
<TextBlock Width="200" Text="{Binding Name}" />
<ItemsControl ItemsSource="{Binding Columns}">
<!-- Use a horizontal StackPanel to display columns -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Using a grid approach might make things more complicated than they should be. Have you tried changing the template of a listview, or to use the DataGrid instead for this purpose?
For an example, take a look at this project: http://www.codeproject.com/Articles/25058/ListView-Layout-Manager
Or this one: http://www.codeproject.com/Articles/16009/A-Much-Easier-to-Use-ListView
If you go with the Grid, I believe you'll have to add a lot of code behind to manage the amount of columns and rows, their size, the cell content... Whereas a ListView/DataGrid will let you do this dynamically through Templates.
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