我想在MVVM中使用ListBox的SelectionChangeEvent

时间:2019-01-18 08:31:35

标签: c# mvvm

首先,我会英语。所以,如果您说您听不懂,我感到很抱歉。

我有2个ListBox的WPF应用程序。我想将应用程序重新制作为MVVM。

但是我不知道将SelectionChanged事件编码为MVVM。

我尝试了这段代码。

在查看代码中,它包含注释。我添加的代码然后得到了我朋友的建议。 (但它也不起作用。)

//查看

    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));
        }
    }
}

我想做这些...

@如果单击“红色”,则项目列表将ListBox显示为“ apple”和“ sun”。然后,如果我单击蓝色...是相同的。

@我要单击许多颜色!因此,如果我单击红色和蓝色,则项目列表会显示“苹果”,“太阳”,“海洋”和“天空”。 (但我不在乎列表顺序)

@列表(颜色和项目)内容不同。所以我想将内容设置为动态,并将项目添加为动态。

我应该重新制作这段代码吗?

2 个答案:

答案 0 :(得分:2)

在Xaml中,您需要将SelectedItem属性绑定到字符串(而不是列表/集合)

<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));
}

我还建议在从集合中添加/删除项目时,使用ItemList代替ItemListVal(后备字段)。

答案 1 :(得分:1)

在您的xaml文件中,将SelectedItem绑定到作为集合的SelectColorList,要使其正确,应将其绑定到单个值(在您的情况下为某些字符串属性),而不是集合。
更新
首先,我想提到无法进行多重绑定,这就是为什么我们将使用事件SelectionChanged的原因。
例如,这是您的“视图”,其中包含两个列表框,其中一个将包含颜色源,该颜色源可以进行多种选择:

<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>


您的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);
    }
}


最后,您的视图模型:

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
}


这就是完成的方法。希望这个答案对您有帮助