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:
Item
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;
}
}
CodePudding user response:
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));
}