【问题标题】:WPF Merge ItemsSource ListsWPF 合并项目源列表
【发布时间】:2026-01-30 07:40:01
【问题描述】:

我正在处理后端类中的 2 个列表。每个列表都是不同的类型。想要呈现用户单个列表(包含两个列表的union),其中选择此列表中的项目时项目的详细信息显示。

代码如下所示:

我的后端类看起来像这样

public ObservableCollection<Person> People {get;}
public ObservableCollection<Product> Products {get;}

我的 XAML 看起来像这样

<ListBox x:Name="TheListBox" ItemsSource={Some Expression to merge People and Products}>
   <ListBox.Resources>
         People and Product Data Templates
   </ListBox.Resources>
</ListBox>
      ...
<ContentControl Content={Binding ElementName=TheListBox, Path=SelectedItem }>
   <ContentControl.Resources>
         Data Templates for showing People and Product details
   </ContentControl.Resources>
</ContentControl>

有什么建议吗?

【问题讨论】:

  • 我正在寻找类似的东西,我可以直接从标记中使用它并且不会污染我的视图模型界面。它应该基本上解决了视图模型提供的项目之间的不匹配,这些项目可能是多个集合或只是几个独立的属性与 WPF 所期望的,这是一个单一的可枚举。理想情况下,我什至想直接在标记中添加项目,这些项目甚至不对应于视图模型中的任何内容,而是合并到同一个列表中。

标签: wpf mvvm listbox binding itemssource


【解决方案1】:

您可以为此使用CompositeCollection。看看这个question

【解决方案2】:

我不明白您为什么不在 ViewModel 中公开这样的属性:

ObservableCollection<object> Items 
{
  get 
  {
    var list = new ObservableCollection<object>(People);
    list.Add(Product);
    return list;
  }
}

然后在您的 xaml 中执行以下操作:

<ListBox x:Name="TheListBox" ItemsSource={Binding Items}>
   <ListBox.Resources>
         People and Product Data Templates
   </ListBox.Resources>
</ListBox>
      ...
<ContentControl Content={Binding ElementName=TheListBox, Path=SelectedItem }>
   <ContentControl.Resources>
         Data Templates for showing People and Product details
   </ContentControl.Resources>
</ContentControl>

更新:

如果您需要以不同方式操作模型,请执行以下操作:

ObservableCollection<object> _Items 
ObservableCollection<object> Items 
{
  get 
  {
    if (_Items == null)
    {
      _Items = new ObservableCollection<object>();
      _Items.CollectionChanged += EventHandler(Changed);
    }
    return _Items;
  }
  set 
  { 
    _Items = value;
    _Items.CollectionChanged += new CollectionChangedEventHandler(Changed);
  }
}

void Changed(object sender,CollectionChangedEventArgs e)
{
  foreach(var item in e.NewValues)
  {
    if (item is Person)
      Persons.Add((Person)item);
    else if (item is Product)
      Products.Add((Product)item);
  }
}

这只是一个例子。但是,如果您修改上述内容以满足您的需求,它可能会让您达到您的目标

【讨论】:

  • 我考虑过以类似于您建议的方式进行操作。让我的场景变得复杂的是,我需要有一种方法可以通过 UI 从列表中添加和删除项目。
【解决方案3】:

我发现了一篇博文 here,它让我大吃一惊。我使用作者 AggregateCollection 和一个多值转换器来完成工作。

【讨论】: