You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中如何将ItemsControl内ComboBox的选择绑定至非ItemSource列表

WPF MVVM 手动排序实现方案

先解决你代码里的几个关键问题,再给你修正后的完整代码:

问题根源

  1. 选中值共享:你用Enumerable.Repeat(new ItemSelectionPart(items), items.Count)时,本质是把同一个ItemSelectionPart实例重复添加了N次,所有ComboBox绑定的都是同一个Selection属性,选一个自然全跟着变。
  2. DisplayMemberPath写错了:这个属性直接填要显示的属性名字符串(比如"Id"或"Name")就行,不需要用{Binding}语法。
  3. 没加属性变更通知:你的ItemSelectionPart和ViewModel都没实现INotifyPropertyChanged,选完值UI不会同步,ViewModel也收不到变化。
  4. SelectedValue用错了:你的Selection是Item类型,直接用SelectedItem绑定就行,SelectedValue要配合SelectedValuePath使用,反而麻烦。

修正后的完整代码

1. 通用通知基类(避免重复写INotifyPropertyChanged)

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 修改Item类(可选,后续属性变更时UI能自动更新)

public class Item : ObservableObject
{
    private int _id;
    private string _name;

    public Item(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public int Id
    {
        get => _id;
        set
        {
            _id = value;
            OnPropertyChanged();
        }
    }

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }
}

3. 修正ItemSelectionPart类

每个实例独立,选值变化能通知UI:

public class ItemSelectionPart : ObservableObject
{
    private Item _selection;

    public ItemSelectionPart(List<Item> allItems)
    {
        AllItems = allItems;
    }

    public List<Item> AllItems { get; }

    public Item Selection
    {
        get => _selection;
        set
        {
            _selection = value;
            OnPropertyChanged();
        }
    }
}

4. 重写ViewModel

循环创建独立的ItemSelectionPart实例,添加获取排序结果的方法:

public class ComboViewModel : ObservableObject
{
    public string Test2 { get; set; }
    public List<Item> Items { get; set; }
    public ObservableCollection<ItemSelectionPart> ItemsSelection { get; set; }

    public ComboViewModel()
    {
        Test2 = "test";
        Items = new List<Item>
        {
            new Item(100, "Entry #1"),
            new Item(101, "Entry #2"),
            new Item(102, "Entry #3"),
            new Item(103, "Entry #4")
        };

        // 循环创建独立实例,解决选中值共享问题
        ItemsSelection = new ObservableCollection<ItemSelectionPart>();
        foreach (var _ in Items)
        {
            ItemsSelection.Add(new ItemSelectionPart(Items));
        }
    }

    // 获取最终排序结果
    public List<Item> GetSortedItems()
    {
        return ItemsSelection.Select(s => s.Selection).Where(i => i != null).ToList();
    }
}

5. 修正XAML

<Window x:Class="TestingComboBox.MainWindow"
        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:TestingComboBox"
        d:DataContext="{d:DesignInstance Type=local:ComboViewModel}"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <ItemsControl ItemsSource="{Binding ItemsSelection}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ComboBox Margin="5"
                              ItemsSource="{Binding AllItems}"
                              DisplayMemberPath="Name" <!-- 要显示Id就改成"Id" -->
                              SelectedItem="{Binding Selection}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <!-- 添加按钮测试获取排序结果 -->
        <Button Margin="5" Content="获取排序结果" Click="GetSortedItems_Click"/>
    </StackPanel>
</Window>

6. 主窗口添加按钮事件

public partial class MainWindow : Window
{
    private ComboViewModel _viewModel;

    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new ComboViewModel();
        DataContext = _viewModel;
    }

    private void GetSortedItems_Click(object sender, RoutedEventArgs e)
    {
        var sortedItems = _viewModel.GetSortedItems();
        // 此处可将结果存入目标列表,或弹窗查看效果
        MessageBox.Show(string.Join("\n", sortedItems.Select(i => $"{i.Id}: {i.Name}")));
    }
}

额外优化建议

  • 如果要禁止重复选择同一个Item,可以在ViewModel中维护已选中集合,每次选值时过滤掉已选Item,更新每个ItemSelectionPart的可选列表。
  • 若需要初始时每个ComboBox默认选中不同Item,在创建ItemSelectionPart时给Selection赋值即可。

内容的提问来源于stack exchange,提问作者thatguy14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:35:31