如何使用 MVVM 模式引发/处理 WPF 的
SelectionChanged
ComboBox
事件?我想要的是当
ComboBox
项目选择改变时做一些操作。我怎样才能以 MVVM 方式实现它?
MVVM解决方案:
将
ItemsSource
的 SelectedItem
和 ComboBox
属性绑定到 ViewModel 中的属性:
<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem}"/>
在MainViewModel.cs中:
public ObservableCollection<string> MyItems { get; set; }
private string _mySelectedItem;
public string MySelectedItem
{
get { return _mySelectedItem; }
set
{
// Some logic here
_mySelectedItem = value;
}
}
代码隐藏解决方案:
如果你不想使用MVVM,你可以添加use this:
<ComboBox SelectionChanged="ComboBox_SelectionChanged" />
并将其添加到 MainWindow.xaml.cs 中:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Some logic here
}
我非常喜欢这种方法。
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>
您的 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"));
}
}
}
}
}
之前发布的 XAML 是正确的:
<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem}"/>
只是上面存在的解决方案的增强,如果您正在使用Prism Library
(如果没有,那么现在停止阅读,没有什么适合您)
我真的很喜欢这个解决方案,我认为它比任何其他解决方案都要好,我只是想对 Prism 库提供的解决方案进行一些小的增强。
该解决方案正在使用
<i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />
注意
i:
之前的 InvokeCommandAction
。这意味着 InvokeCommandAction
类存在于 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
命名空间中。这很好,但请注意,Prism 库具有完全相同的同名类 InvokeCommandAction
。它只是存在于另一个命名空间中,即 xmlns:prism="http://prismlibrary.com/"
命名空间中。
所以实际上你可以替换下面的XAML
<i:InvokeCommandAction Command="{Binding RegionChangedCmd}" />
使用此 XAML
<prism:InvokeCommandAction Command="{Binding RegionChangedCmd}" />
好的,我们可以这么做,有什么好处呢?
要注意到好处,请在 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>
}
如果使用 <i:InvokeCommandAction>
,则参数为
null如果您使用
<prism:InvokeCommandAction>
,则 e 参数为 NOT null
由于您没有提供任何有关从何处处理选择更改的信息,我将假设最常见的场景 - 在底层 ViewModel 中处理。根据 MVVM ViewModel 不应该了解有关 View 的任何信息,因此您不能直接从 ViewModel 订阅 View 控件的事件。但是您可以将 ViewModel 的属性绑定到
SelectedItem
或
SelectedIndex
,这样它就会在选择更改时触发。
<ComboBox
SelectedIndex="{Binding SelectedIndexPropertyName}"
... />
还有其他解决方案通过
view.DataContext
访问 ViewModel 来在视图后面的代码中进行处理,但我建议避免这种做法,这是解决问题的情况。
从 .NET Framework 4.6.2 和 .NET Core 开始,上述解决方案不起作用,它们适用于旧版本的 WPF。
这是新方法
Microsoft.Xaml.Behaviors.Wpf包
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
<ComboBox ItemsSource="{Binding Items}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
注意:代码根本没有任何变化,唯一需要的是Nuget包和更新命名空间