如何在 wpf 中使用 MVVM 处理 ComboBox 的 SelectionChanged 事件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8666256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:13:43  来源:igfitidea点击:

How to handle the SelectionChanged event of ComboBox with MVVM in wpf?

wpfmvvmwpf-controls

提问by Tanya

How to raise / handle the SelectionChangedevent of WPF's ComboBoxusing the MVVM pattern?
Explain in detail please I am new to WPF.

如何使用 MVVM 模式引发/处理SelectionChangedWPF 的事件ComboBox
请详细解释我是WPF的新手。

What I want, is to do some operations when the ComboBoxitem selection changed. How can I achieve it, in an MVVM way?

我想要的是在ComboBox项目选择改变时做一些操作。我怎样才能以 MVVM 的方式实现它?

回答by snurre

MVVM solution:

MVVM 解决方案

Bind the ItemsSourceand SelectedItemproperties of the ComboBoxto properties in your ViewModel:

将 的ItemsSourceSelectedItem属性绑定ComboBox到 ViewModel 中的属性:

<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem}"/>

In MainViewModel.cs:

在 MainViewModel.cs 中:

public ObservableCollection<string> MyItems { get; set; }

private string _mySelectedItem;
public string MySelectedItem
{
  get { return _mySelectedItem; }
  set
  {
    // Some logic here
    _mySelectedItem = value;
  }
}

Code-behind solution:

代码隐藏解决方案

If you don't want to use MVVM, you can add use this:

如果你不想使用 MVVM,你可以添加使用这个:

 <ComboBox SelectionChanged="ComboBox_SelectionChanged" />

And add this in MainWindow.xaml.cs:

并在 MainWindow.xaml.cs 中添加:

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // Some logic here
}

回答by Blackey

I'm a big fan of this method.

我是这种方法的忠实粉丝。

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<ComboBox Grid.Column="2"  DisplayMemberPath="Data.name" ItemsSource="{Binding Model.Regions}" SelectedItem="{Binding Model.SelectedRegion}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>

回答by Steven Licht

Your ViewModel needs to implement INotifyPropertyChanged.

您的 ViewModel 需要实现 INotifyPropertyChanged。

public class MyViewModel : INotifyPropertyChanged
{
    private string _mySelectedItem;
    public string MySelectedItem
    {
        get
        {
            return _mySelectedItem;
        }
        set
        {
            if (_mySelectedItem != value)
            {
                _mySelectedItem = value;
                // Perform any pre-notification process here.
                if (null != PropertyChanged)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("MySelectedItem"));
                }
            }
        }
    } 
}

The previously posted XAML is correct:

之前发布的 XAML 是正确的:

<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem}"/> 

回答by Hakan F?st?k

Just an enhancement of this solutionwhich exists above, In case you are using Prism Library
(if not, then stop reading now, there is nothing for you)

只是上面存在的这个解决方案的增强,如果你正在使用棱镜库
(如果没有,那么现在停止阅读,没有什么适合你)

I really like this solution and I think it is better than any other solution, I just want to make a small enhancement to that solution provided by the Prism Library.

我真的很喜欢这个解决方案,我认为它比任何其他解决方案都要好,我只是想对 Prism 库提供的解决方案做一个小的改进。

that solution is using

该解决方案正在使用

<i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />

notice the i:before the InvokeCommandAction. It means that the InvokeCommandActionclass exists in the xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"namespace. This is good and fine, but notice that the Prism library has exactly the same class with the same name InvokeCommandAction. It just exists in another namespace, in the xmlns:prism="http://prismlibrary.com/"namespace.

注意i:之前的InvokeCommandAction。这意味着InvokeCommandAction该类存在于xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"命名空间中。这很好也很好,但请注意 Prism 库具有完全相同的同名类InvokeCommandAction。它只是存在于另一个命名空间中,在xmlns:prism="http://prismlibrary.com/"命名空间中。

So actually you can replace the following XAML

所以实际上你可以替换下面的XAML

<i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />

with this XAML

使用这个 XAML

<prism:InvokeCommandAction Command="{Binding RegionChangedCmd}" />

OK, we can do this, what is the benefit?
To notice the benefit, write the following command in the ViewModel

好的,我们可以这样做,有什么好处?
要注意好处,请在 ViewModel 中编写以下命令

public ICommand RegionChangedCmd { get; }

public ViewModelConstructor() 
{
   RegionChangedCmd = new DelegateCommand<SelectionChangedEventArgs>(RegionChangedCmdExecuted);
}

public void RegionChangedCmdExecuted(SelectionChangedEventArgs e)
{
   // e parameter is null     if you use <i:InvokeCommandAction>
   // e parameter is NOT null if you use <prism:InvokeCommandAction>
}

e parameter is nullif you use <i:InvokeCommandAction>
e parameter is NOT nullif you use <prism:InvokeCommandAction>

如果使用e 参数为null如果使用<i:InvokeCommandAction>
e 参数为NOT null如果使用<prism:InvokeCommandAction>

回答by sll

As first let's make things clear - you can not change event rather you can subscribe to.

首先让我们把事情说清楚——你不能改变事件而你可以订阅。

Since you've not provided any information regarding where from you want to handle selection changes I will assume most common scenario - handling in the underlying ViewModel. According to MVVM ViewModel should not know anything about View so you can not subscribe directly from ViewModel to the event of a View's control. But you can bind a property of ViewModel to either SelectedItemor SelectedIndexso it would trigger whilst selection changes.

由于您没有提供任何有关从何处处理选择更改的信息,我将假设最常见的情况 - 在底层 ViewModel 中处理。根据 MVVM ViewModel 不应该对 View 一无所知,因此您不能直接从 ViewModel 订阅 View 控件的事件。但是您可以将 ViewModel 的属性绑定到任一SelectedItemSelectedIndex这样它会在选择更改时触发。

<ComboBox 
       SelectedIndex="{Binding SelectedIndexPropertyName}" 
       ... />

There are other solutions doing handling in code behind of a View by accessing a ViewModel via view.DataContextbut I would suggest avoid such practice, this are work around cases.

还有其他解决方案通过访问 ViewModel 通过在视图后面的代码中进行处理,view.DataContext但我建议避免这种做法,这是解决情况。