I want to build an ui with a dynamic grid. At least I think a grid is the way to go.
The controls of each cell should be the same, f.e. a TextBox
.
Each row can have a different number of cells and I thought about using the ColumnSpan
property to make the ui look like
First row, 2 cells
Second row, 3 cells
Third row, 1 cell
Each cell should be part of an f.e. ObservableCollection<MyCellClass>
and should have properties like Row
, Column
, Columnspan
, Text
.
I know how to build a dynamic grid but I don't know how to set the content of the cells via a template and how to databind the textbox.
Maybe my approach isn't the best and you got some other idea to solve my problem.
You may use a Grid as the ItemsPanel
of an ItemsControl, and bind the ItemsSource
property to your ObservableCollection.
Assuming that your cell class looks like this:
public class Cell
{
public int Column { get; set; }
public int ColumnSpan { get; set; }
public int Row { get; set; }
public int RowSpan { get; set; }
public string Text { get; set; }
}
the XAML may be written like shown below:
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Grid.Column" Value="{Binding Column}"/>
<Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}"/>
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.RowSpan" Value="{Binding RowSpan}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The following piece of code would initialize two cells of the ItemsControl:
public MainWindow()
{
InitializeComponent();
var cells = new ObservableCollection<Cell>();
cells.Add(new Cell { Column = 0, Row = 0, ColumnSpan = 1, RowSpan = 1, Text = "Cell 1" });
cells.Add(new Cell { Column = 2, Row = 2, ColumnSpan = 2, RowSpan = 1, Text = "Cell 2" });
DataContext = cells;
}
Why not using something like this?
public class ItemVm
{
// here you can put your desired properties,
// although you won't need something like ColumnsSpan etc.
}
As underlying structure (viewmodel) for your grid you could use the following property:
public ObservableCollection<ObservableCollection<ItemVm>> Rows { get; } // just an illustration
Now you only need a ListView
(or something similar), whose ItemTemplate
is again a ListView
(or something similar). The ItemTemplate
of the inner ListView
will be the visual representation of ItemVm
.
Please note, that I'm describing an approach according to the MVVM pattern. So you will need a base class for the viewmodels. But you can find plenty of frameworks on the WWW.