Как привязать ListView к нескольким коллекциям, хранящимся в одной ViewModel в WPF?

у меня есть 2 коллекции, которые я хочу привязать к отдельной GridViewColumn на ListView:

public class EffectView : INotifyPropertyChanged
{

    ObservableCollection<Effect> effects;
    public ObservableCollection<Effect> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "Effects" );
        }
    }

    ObservableCollection<EffectDescription> descriptions;
    public ObservableCollection<EffectDescription> Descriptions
    {
        get { return this.descriptions; }
        set
        {
            this.descriptions = value;
            this.RaisePropertyChanged ( "Descriptions" );
        }
    }
}

Я могу сделать это:

<ListView ItemsSource="{Binding EffectView.Effects}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding ?}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

но тогда все ограничено EffectView.Effects, но я хочу, чтобы масштаб по умолчанию EffectView поэтому я могу легко назначить несколько коллекций ListView.

что-то типа:

<ListView ItemsSource="{Binding EffectView}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effects Path=Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effects Path=Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Descriptions Path=Usage}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

любой способ сделать это?

2 ответов


на ItemsSource из ListView является коллекция чьи элементы будут отображаться в списке. Поэтому подумайте на мгновение о том, что вы просите ListView сделать:

  • в качестве исходной коллекции используйте то, что не является коллекцией, но содержит их
  • для каждой строки в списке отобразите элемент из одной коллекции и элемент из другой коллекции

обратите внимание на этот второй момент: каждая строка должна отображать какой-то элемент из коллекции Events и некоторого элемента из коллекции Descriptions.

какой пункт он должен выбрать из каждого? Какова связь между элементами в двух коллекциях?

это появляется то, что вам действительно нужно, это коллекция объектов, которая содержит и событие и описание. Затем можно выполнить привязку к этой коллекции для отображения элементов обеих сущностей. Примерно, что-то вроде это:

public class EffectView : INotifyPropertyChanged
{

    ObservableCollection<EffectsAndDescriptions> effects;
    public ObservableCollection<EffectAndDescriptions> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "EffectsAndDescriptions" );
        }
    }

}

internal class EffectsAndDescriptions
{
    public Effect Effect { get; set; }
    public Description Description { get; set; }
}

теперь вы можете привязаться к коллекции EffectsAndDescriptions (обратите внимание, что это предполагает DataContextродитель is EffectView)

<ListView ItemsSource="{Binding EffectsAndDescriptions}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effect.Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effect.Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Description.Usage}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

Это действительно невозможно. ItemsSource ожидает, что будет передано что-то, что, как минимум, реализует IEnumerable. Даже если вы реализовали IEnumerable в своем EffectView, вам нужно будет обернуть эффект и EffectDescription в один объект для возврата.

вы можете привязать ListView к коллекции эффектов, а затем использовать пользовательский IValueConverter для получения эффекта и возврата описания. Но я не уверен, что это подходит к вашей ситуации.

ваш лучший выбор было бы включить объект-оболочку (т. е. EffectWithDescription), который включает как ваш эффект, так и Ваше EffectDescription. Затем предоставьте коллекцию объектов EffectWithDescription. Вам нужно будет убедиться, что эта новая коллекция синхронизируется с другими коллекциями.