user10184747
user10184747

Reputation:

I want use SelectionChangeEvent of ListBox in MVVM

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

Answers (2)

Sergey Anisimov
Sergey Anisimov

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

fhnaseer
fhnaseer

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

Related Questions