Reputation:
First of all, I'm good at English. So I'm sorry if I say that you cannot understand.
I have WPF Application with 2 ListBoxs. And I want remake the app as MVVM.
But I don't know coding SelectionChanged Event as MVVM.
I tried this code.
In View code, it contains Comment. It's code that I add then I get advice my friend. (But It's not work, too.)
//View
xmlns:xcad="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox HorizontalAlignment="Left" Height="56" Margin="64,67,0,0" VerticalAlignment="Top" Width="380" SelectedItem="{Binding SelectColorList}" ItemsSource="{Binding ColorList}"/>
<ListBox HorizontalAlignment="Left" Height="56" Margin="64,182,0,0" VerticalAlignment="Top" Width="380" ItemsSource="{Binding ItemList}"/>
<!--<xcad:CheckListBox HorizontalAlignment="Left" Height="56" Margin="64,67,0,0" VerticalAlignment="Top" Width="380" SelectedItemsOverride="{Binding SelectColorList}" ItemsSource="{Binding ColorList}"/>
<xcad:CheckListBox HorizontalAlignment="Left" Height="56" Margin="64,182,0,0" VerticalAlignment="Top" Width="380" ItemsSource="{Binding ItemList}"/>-->
<Label Content="Color" HorizontalAlignment="Left" Height="24" Margin="65,38,0,0" VerticalAlignment="Top" Width="65"/>
<Label Content="Item" HorizontalAlignment="Left" Height="24" Margin="64,153,0,0" VerticalAlignment="Top" Width="65"/>
</Grid>
//CodeBehinde
private MainViewModel viewmodel;
public MainWindow()
{
InitializeComponent();
viewmodel = new MainViewModel();
this.DataContext = viewmodel;
}
//ViewModel
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> ColorListVal;
public ObservableCollection<string> ColorList
{
get { return ColorListVal; }
set
{
ColorListVal = value;
NotifyPropertyChanged("ColorList");
}
}
private ObservableCollection<string> SelectColorListVal = new ObservableCollection<string>();
public ObservableCollection<string> SelectColorList
{
get { return SelectColorListVal; }
set
{
SelectColorListVal = value;
NotifyPropertyChanged("SelectColorList");
ItemListVal.Clear();
for (int i = 0; i < SelectColorList.Count; i++)
{
switch (SelectColorList[i])
{
case "red":
ItemListVal.Add("apple");
ItemListVal.Add("sun");
break;
case "blue":
ItemListVal.Add("sea");
ItemListVal.Add("sky");
break;
case "yellow":
ItemListVal.Add("lemmon");
ItemListVal.Add("pineapple");
break;
case "green":
ItemListVal.Add("vegetable");
ItemListVal.Add("greentea");
break;
}
}
}
}
private ObservableCollection<string> ItemListVal;
public ObservableCollection<string> ItemList
{
get { return ItemListVal; }
set
{
ItemListVal = value;
NotifyPropertyChanged("ItemList");
}
}
public MainViewModel()
{
ColorListVal = new ObservableCollection<string>() { "red", "blue", "yellow", "green" };
ItemListVal = new ObservableCollection<string>() { "not selected!" };
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
I want do these...
@If I click "red", the item list shows "apple" and "sun" as ListBox. Then if I click blue...it's same.
@I Want click many color! So if I click red and blue, the item list shos "apple", "sun", "sea" and "sky". (But I don't care the list order)
@The list(both of color and item) contens is not same. So I want set content as dynamic and add items as dynamic.
What should I remake this code?
Upvotes: 1
Views: 92
Reputation: 895
in your xaml file you bind SelectedItem to SelectColorList, which is a collection, to make it correct you should bind to a single value (some string property in your case), not to collection.
UPDATE:
First of all, I want to mention that there is no way for multiple binding, that's why we will use an event SelectionChanged.
For example, this is your View, which contains two list boxes, one of them will contain a source of colors which will be able for multiple selections:
<Window x:Class="WpfApp1.MainWindow">
<StackPanel Orientation="Horizontal">
<!-- First list box contains colors -->
<ListBox
ItemsSource="{Binding ColorList}"
SelectionMode="Extended"
SelectionChanged="ListBox_SelectionChanged"
/>
<!-- Second list box will contain result values -->
<ListBox
ItemsSource="{Binding ItemList}"
/>
</StackPanel>
</Window>
Your MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Set data context
DataContext = new ViewModel();
}
/// <summary>
/// Called when selection is changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
// Get event sender
var listBox = sender as ListBox;
// Create temp list for selected items
var tempList = new List<string>();
foreach (string item in listBox.SelectedItems)
{
tempList.Add(item);
}
(DataContext as ViewModel).OnSelectionChanged(tempList);
}
}
And finally, your view model:
public class ViewModel : INotifyPropertyChanged
{
#region Private Fields
private ObservableCollection<string> mColorList;
private ObservableCollection<string> mItemList;
#endregion
#region Public Properties
/// <summary>
/// This is list box 1 items source with colors
/// </summary>
public ObservableCollection<string> ColorList
{
get { return mColorList; }
set
{
mColorList = value;
NotifyPropertyChanged(nameof(ColorList));
}
}
/// <summary>
/// This is list box 2 items with results
/// </summary>
public ObservableCollection<string> ItemList
{
get { return mItemList; }
set
{
mItemList = value;
NotifyPropertyChanged(nameof(ItemList));
}
}
#endregion
#region Constructor
public ViewModel()
{
// Initialization
ColorList = new ObservableCollection<string>() { "red", "blue", "yellow", "green" };
ItemList = new ObservableCollection<string>() { "not selected!" };
}
#endregion
#region Public Methods
/// <summary>
/// Called when selection is changed
/// </summary>
/// <param name="selectedItems"></param>
public void OnSelectionChanged(IEnumerable<string> selectedItems)
{
ItemList.Clear();
foreach (var item in selectedItems)
{
switch (item)
{
case "red":
ItemList.Add("apple");
ItemList.Add("sun");
break;
case "blue":
ItemList.Add("sea");
ItemList.Add("sky");
break;
}
}
}
#endregion
#region InterfaceImplementation
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
This is how it can be done. Hope this answer will help you
Upvotes: 0
Reputation: 7277
In Xaml, you need to bind SelectedItem property to a string (not a list/collection)
<ListBox SelectedItem="{Binding SelectColor}" ItemsSource="{Binding ColorList}"/>
<ListBox ItemsSource="{Binding ItemList}"/>
ViewModel,
private string _selectedColor;
public string SelectedColor
{
get => _selectedColor;
set
{
_selectedColor = value;
ItemList.Clear();
switch (_selectedColor)
{
case "red":
ItemList.Add("apple");
ItemList.Add("sun");
break;
…
}
NotifyPropertyChanged(nameof(SelectedColor));
}
Also I would suggest to use ItemList
instead of ItemListVal
(backing field) when adding/removing items from the collection.
Upvotes: 1