简体   繁体   中英

C# WPF ListView MVVM ObservableCollection inside of an ObservableCollection

I have an ObservableCollection of Team (ObservableCollection<Team>) . In my Team class I have an ObservableCollection of "Actor" (ObservableCollection). Now I want display the actors in a Listview in with mvvm pattern.

Anyone have a solution? I did not found anything on google to show the actors in my Listview .

Thanks in advance.

<Window x:Class="Room.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Room.Views"
    xmlns:localBind="clr-namespace:Room.ViewModels"
    mc:Ignorable="d"
    Title="" Height="300" Width="800">

<Window.DataContext>
    <localBind:MainViewModel/>
</Window.DataContext>

<Grid>
    <ListView Margin="10" ItemsSource="{Binding Teams}"
              SelectedItem="{Binding SelectedActor}" >
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding Id}"/>
                <GridViewColumn Header="Niggname" Width="160" 
                                DisplayMemberBinding="{Binding Name}" />
            </GridView>
        </ListView.View>
    </ListView>
</Grid>

From this other stackoverflow post :

If the list is nested, you have a tree, for which you can use a HierarchicalDataTemplate and display in a TreeView or nested ListViews.

If you want to view in a flat list, have your ViewModel flatten the tree, assuming you are using an MVVM pattern.

Your listview is showing each individual Team as an item. Because you have nested collections ( Teams is a collection of collections of Actors ), your Id and Name bindings aren't binding to the Actor items but to the Team items.

My initial solution was to go deeper and put a listview inside of a listview

<ListView ItemsSource="{Binding Teams}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ListView Margin="10" ItemsSource="{Binding Actors}"
                          SelectedItem="{Binding SelectedActor}" >
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding Id}"/>
                        <GridViewColumn Header="Name" Width="160" 
                                            DisplayMemberBinding="{Binding Name}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

with the following result:

第一个解决方案嵌套 ListViews

However, as you can see I can only select a Team . I can select an Actor within each list but this is not what you want (under running assumption you want a single list).

What was easier for me was to flatten the tree in C#. Assuming that I have a flat list of actors (regardless of team) I can do this:

<ListView ItemsSource="{Binding AllActors}"
          SelectedItem="{Binding SelectedActor}" >
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding Id}"/>
            <GridViewColumn Header="Name" Width="160" 
                            DisplayMemberBinding="{Binding Name}" />
        </GridView>
    </ListView.View>
</ListView>

with the following result: 第二种解决方案扁平化列表

How you decide to flatten the list is up to you. Make sure to implement INPC on the Team class as well since modifying a Team inside an ObservableCollection<Team> won't tell the collection to update the binding without INPC.

If you are strictly following MVVM, I would possibly recommend creating some Dependency Property s in your control's code behind and flatten the list there.

My rationale is that this operation is purely cosmetic. We aren't performing business logic or changing data when we flatten the list; we are only prepping it for how we want to view it. So, we shall put the code to that in the code-behind as opposed to the VM. This is a bit more difficult though since now you have to make sure you bind correctly from VM <-> DP <-> Control as opposed to VM <-> Control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM