0

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.

pfinferno
  • 1,779
  • 3
  • 34
  • 62
  • if you are binding iitems then use an items control (i would suggest either ItemsControl or ListView) only user a Grid for fixed layouts, if you show the attempt iwth the items control we can probably suggest where you went wrong – MikeT Dec 06 '16 at 16:48
  • Added the itemscontrol part to the xaml. Those two textboxes appear in the upper lefthand corner of my grid. I want them to appear below the last existing row of the grid. – pfinferno Dec 06 '16 at 16:55
  • 1
    the items control doesn't add items to the grid it adds them to itself, remove the grid entirely, give me a few and ai'll put up an example for you – MikeT Dec 06 '16 at 16:58
  • 1
    Check out [this one](http://stackoverflow.com/questions/2913854/wpf-dynamic-layout-with-itemscontrol-and-grid). – dymanoid Dec 06 '16 at 16:59
  • @dymanoid that looks promising, going to try what's suggested there. – pfinferno Dec 06 '16 at 17:04

2 Answers2

1

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}" />
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Do I need the stackpanel there? Or would just binding the grid.columns be enough? Because each textbox would be in a different column. – pfinferno Dec 06 '16 at 17:26
  • 1
    I edited my answer. You won't need the StackPanel if you intend to add the TextBoxes to different columns of the Grid. Then you can add them to the Grid directly. – mm8 Dec 06 '16 at 17:34
  • One more question! I have a lot of stuff in the 'main' grid right now. If I add the itemscontrol into the grid, and do what you did above, will rows still be added to the 'main' grid? – pfinferno Dec 06 '16 at 17:53
  • I tried it out, they are being added but they go past the end of the grid, and the main grid doesn't expand to make up for it. – pfinferno Dec 06 '16 at 18:02
  • 1
    The rows of the ItemsControl are not added to the main grid but you should add the ItemsControl itself to the main grid by settings its attached Grid.Row property. – mm8 Dec 06 '16 at 18:46
1

ok what your Items control is doing is saying show a list of items in the 0,0 grid cell

what you need is to put the grid inside the list easiest way is a GridView

eg

<ListView ItemsSource="{Binding VehCollection}">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Depth}"/>
            <GridViewColumn DisplayMemberBinding="{Binding Alt}"/>
            <GridViewColumn/>
            <GridViewColumn/>
        </GridView>
    </ListView.View>

another option would be to set the item template to a grid

<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>
                <TextBox Text="{Binding Alt}" Grid.Column="0"/>
                <TextBox Text="{Binding Depth}"  Grid.Column="1"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ItemsControl>
MikeT
  • 5,398
  • 3
  • 27
  • 43
  • Would those automatically form a new row under the existing rows? – pfinferno Dec 06 '16 at 17:17
  • 1
    the items control will make a new Item for every new item added to the observable collection, it will then use either the Grid view or template to format the appearance of that item – MikeT Dec 06 '16 at 17:20