I recently finished my first MVVM styled app which had a set number of columns/rows and controls in them.
What I'm trying to do now is, based on the number of items in an observableCollection<myClass>
, add a row to the main grid filled with textboxes bound to properties in each item of the observableCollection.
So for instance here's a viewmodel example:
public class VehiclesViewModel : ObservableObject
{
private ObservableCollection<Vehicle> _vehCollection;
public ObservableCollection<Vehicle> VehCollection
{
get
{
return this._vehCollection;
}
set
{
if (null != value)
{
this._vehCollection= value;
OnPropertyChanged("VehCollection");
}
}
}
}
Here's the model class:
public class Vehicle : INotifyPropertyChanged
{
private double _alt;
public double Alt
{
get { return this._alt; }
set
{
this._alt = value;
base.OnPropertyChanged("Alt");
}
}
private double _depth;
public string Depth
{
get { return this._depth; }
set
{
this._depth = value;
base.OnPropertyChanged("Depth");
}
}
}
Here's an example view:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="39.8" />
<ColumnDefinition Width="39.8" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="26" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ItemsControl ItemsSource="{Binding VehCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Alt}" Grid.Column="0" Grid.ColumnSpan="2"/>
<TextBox Text="{Binding Depth}"
Grid.Column="3"
Grid.ColumnSpan="2" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Let's say some function I call adds three items to _vehCollection. When this happens, I want the grid to add three rows beneath the existing rows, with each of those three containing two textboxes that are bound to the properties in my Vehicle class for each of those items. I also want to specify the Grid.Column
they will appear in (they will appearing horizontally on the same row, not vertically).
I tried using an ItemsControl
, which does make the textboxes appear, but it appears at the upper lefthand corner of the grid. I can't get it to appear below the existing rows.
Note: I have a lot more rows/column definitions and other controls inside of the main grid. I don't want to redo all of that.
You could use an ItemsControl with a Grid as its ItemPanel. It will be a bit tricky to dynamically add RowDefinitions to the Grid though. Please check out the following blog post for more information and an example: http://blog.scottlogic.com/2010/11/15/using-a-grid-as-the-panel-for-an-itemscontrol.html.
An easier approach would be to use an ItemsControl with an ItemTemplate that contains a Grid with the desired number of columns. You can then add a Column property of type int to your Vehicle class and bind the Grid.Column attached property of your StackPanel in the ItemTemplate to this one:
<ItemsControl ItemsSource="{Binding VehCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="39.8" />
<ColumnDefinition Width="39.8" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="{Binding Column}">
<TextBox Text="{Binding Alt}" />
<TextBox Text="{Binding Depth}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If each TextBox should be in a column of its own you could add a "Column" property per TextBox to your Vehicle class and bind to these separately:
<TextBox Text="{Binding Alt}" Grid.Column="{Binding AltColumn}" />
<TextBox Text="{Binding Depth}" Grid.Column="{Binding Deptholumn}" />