添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

How to bind selection of combobox in itemscontrol to different list than used as itemssource in WPF

Ask Question

this is concerning WPF and MVVM,

I have a list of items that are unsorted (e.g., "item3, item2, item5, item1, item4"). For each item, I want to display a number of comboboxes equal to the number of items (for n items there needs to be n comboboxes). The user then selects an item for each combo box, essentially sorting the list (resulting in a list of "item1, item2, Item3, item4, item5."). The sorted values are then stored in another list of items. Sorting has to be done by the user.

I have a ViewModel that contains both lists, one with the unsortedItems, the sortedList initially a copy to be the same size.

I manually created a combo box for each item, all with the same Itemssource bound to the unsorted list of items. I then bound each combo box SelectedItem with an index representing which combobox it was i.e., for the first combo box SelectedItem="{binding SortedList[0]}".

The problem with this approach is that I don't know how many items there will be. I thought an Itemscontrol would do the job here but I can't seem to figure out how to embed a combobox inside an itemscontrol so that I can use DisplayMemberPath and SelectedItem properly and not share the selected value. This is what I tried:

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

Item Selection Part

 public class ItemSelectionPart
        public ItemSelectionPart(List<Item> allItems)
            this.allItems = allItems;
        public List<Item> allItems { get; set; }
        public Item Selection { get; set; }

ViewModel

public class ComboViewModel
        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> (Enumerable.Repeat(new ItemSelectionPart(items), items.Count));

Main Window 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
            x:Name="level1"
            ItemsSource="{Binding ItemsSelection}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <ComboBox
                            x:Name="Combo"
                            ItemsSource="{Binding Path=allItems}"
                            DisplayMemberPath="{Binding Path=allItems.Id}"
                            SelectedValue="{Binding Path=Selection}">                           
                        </ComboBox>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Window>

I know that displaymemberpath doesn't work - but left there for what I intended

Main Window.cs

public partial class MainWindow : Window
        private ComboViewModel D;
        public MainWindow()
            InitializeComponent();
            D = new ComboViewModel();
            this.DataContext = D;

Issue with share is, that with Enumerable.Repeat(new ItemSelectionPart(items), items.Count) you create an enumeration with same instance new ItemSelectionPart(items). Later you use the same instance by each combobox, modifying it you impact all comboboxes.

DisplayMemberPath gets just string, not binding.

See the fix:

<ItemsControl ItemsSource="{Binding ItemsSelection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <ComboBox
                x:Name="Combo"
                ItemsSource="{Binding Path=allItems}"
                    DisplayMemberPath="Name"
                    SelectedValue="{Binding Selection}">
                </ComboBox>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
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")
    var selPartList = new List<ItemSelectionPart>(items.Count);
    for (int i = 0; i < items.Count; i++)
        selPartList.Add(new ItemSelectionPart(items));
    ItemsSelection = new ObservableCollection<ItemSelectionPart>(selPartList);
    //ItemsSelection = new ObservableCollection<ItemSelectionPart>(Enumerable.Repeat(new ItemSelectionPart(items), items.Count));
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.