3

I need to display all the information of an object in a DataGrid

ItemsCollectionA, ItemsCollectionB and ItemsCollectionC are all ObservableCollections.

I have a datagrid:

<DataGrid ItemsSource="{Binding Path=itemscollectionA}" HeadersVisibility="All" />

This displays all properties in grid format but the ItemsCollectionB and ItemsCollectionC are appearing as (collection).

enter image description here

How can I get ItemsCollectionB and ItemsCollectionC to expand the grid downward and out to show their properties as well

Tobias
  • 232
  • 1
  • 16
Oliver
  • 651
  • 2
  • 9
  • 17
  • This is because it doesn't know how to display those collections. It's basically calling `.ToString()` on your `ItemsCollectionB` and `ItemsCollectionC`. We need more information to answer your question. as @geedubb asked, what do you want displayed for these? – gleng Nov 04 '13 at 13:22
  • Right now it is telling me there is a collection, I would like all of the values in each item of the collection instead i.e to display the properties called Name or Value that exists in each item of the collection (edit for clarity) – Oliver Nov 04 '13 at 13:31
  • @Oliver Do you **have** to auto-generate the columns? because if not this is fairly easy – Omri Btian Nov 04 '13 at 13:40
  • just an update to say I am still looking at this and may be getting a solution though its not using datagrids anymore as the problem is displaying the collections – Oliver Nov 05 '13 at 18:40

3 Answers3

4

If you can specify the columns instead of auto-generating them, this could be very easy.

Here's an example:

<DataGrid ItemsSource="{Binding Employees}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding EmployeeName}"/>
        <!-- Displays the items of the first collection-->
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ListBox ItemsSource="{Binding Dogs}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <!-- Displays the items of the second collection-->
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ListBox ItemsSource="{Binding Cats}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

ViewModel:

public class MainWindowViewModel : NotificationObject
{
    public MainWindowViewModel()
    {
        Employees = new ObservableCollection<Employee>
        {
            new Employee { EmployeeName = "Steven"},
            new Employee { EmployeeName = "Josh"},
        };
    }

    public ObservableCollection<Employee> Employees { get; set; }
}

Models:

public class Employee
{
    public Employee()
    {
        Dogs = new ObservableCollection<Dog>
        {
            new Dog { Gender = 'M'},
            new Dog { Gender = 'F'},
        };
        Cats = new ObservableCollection<Cat>
        {
            new Cat { Name = "Mitzy" , Kind = "Street Cat"},
            new Cat { Name = "Mitzy" , Kind = "House Cat"}
        };
    }

    public string EmployeeName { get; set; }

    public ObservableCollection<Dog> Dogs { get; set; }

    public ObservableCollection<Cat> Cats { get; set; }
}

public class Dog
{
    public char Gender { get; set; }

    public override string ToString()
    {
        return "Dog is a '" + Gender + "'";
    }
}

public class Cat
{
    public string Name { get; set; }

    public string Kind { get; set; }

    public override string ToString()
    {
        return "Cat name is " + Name + " and it is a " + Kind;
    }
}

Consider ItemsCollectionA as Employees and ItemsCollectionB and ItemsCollectionC as Dogs and Cats. It still uses the ToString to display the Dogs and Cats object's that I overridden, But you can simply set a DataTemplate to the listBox's within the columns to decide how to display your models. Also notice the AutoGenerateColumns="False" on the DataGrid to avoid creating the columns twice.

Hope this helps

Yael
  • 1,566
  • 3
  • 18
  • 25
Omri Btian
  • 6,499
  • 4
  • 39
  • 65
2

A DataGrid can only manage one item source. Everything is row based and the columns are not that intelligent.

Two ways:

  • to combine your data into a new object with both sets of fields (would be the easiest).
  • synchronise 2 datagrids side-by-side.
Aleksey
  • 1,299
  • 9
  • 13
1

Ok it seems like datagrid was entirely the wrong thing I needed here. I made a stackpanel of listbox with the itemssource set to each binding and it's displaying fine

<StackPanel Background="white" HorizontalAlignment="Stretch"  Margin="0">
        <ListBox Background="white" x:Name="BetsListBox"  VerticalAlignment="Stretch" BorderThickness="0" 
                     ItemsSource="{Binding Path=ItemsCollectionA}" Margin="0" Width="Auto" HorizontalAlignment="Stretch" >
            <ListBox.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#F0F0F0"/>
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#F0F0F0"/>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/>
            </ListBox.Resources>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel >
                        <ListBox ItemsSource="{Binding Path=ItemsCollectionB}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlockText="{Binding Path=varA}" />
                                        <TextBlockText="{Binding Path=varB}" />
                                        <TextBlockText="{Binding Path=varC}" />
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                        <ListBox BorderThickness="0" ItemsSource="{Binding Path=ItemsCollectionC}" >
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel  Orientation="Horizontal" >
                                        <TextBlock Text="{Binding Path=VarA}" ToolTip="{Binding Name}"/>
                                        <TextBlock Text="{Binding Path=VarB}" ToolTip="{Binding Name}"/>
                                        <TextBlock Text="{Binding Path=VarC}" ToolTip="{Binding Name}"/>
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox >
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
Oliver
  • 651
  • 2
  • 9
  • 17