【发布时间】:2012-01-29 18:38:33
【问题描述】:
如何使用 MVVM 模式引发/处理 WPF 的 ComboBox 的 SelectionChanged 事件?
请详细解释一下我是WPF的新手。
我想要的是在ComboBox 项目选择发生变化时做一些操作。如何以 MVVM 方式实现它?
【问题讨论】:
标签: wpf mvvm wpf-controls
如何使用 MVVM 模式引发/处理 WPF 的 ComboBox 的 SelectionChanged 事件?
请详细解释一下我是WPF的新手。
我想要的是在ComboBox 项目选择发生变化时做一些操作。如何以 MVVM 方式实现它?
【问题讨论】:
标签: wpf mvvm wpf-controls
首先让我们把事情说清楚 - 您不能更改事件,而是可以订阅。
由于您没有提供任何有关从何处处理选择更改的信息,我将假设最常见的场景 - 在底层 ViewModel 中进行处理。根据 MVVM,ViewModel 不应该对 View 有任何了解,因此您不能直接从 ViewModel 订阅 View 控件的事件。但是您可以将 ViewModel 的属性绑定到 SelectedItem 或 SelectedIndex,这样它就会在选择更改时触发。
<ComboBox
SelectedIndex="{Binding SelectedIndexPropertyName}"
... />
还有其他解决方案通过view.DataContext 访问 ViewModel 来处理 View 背后的代码,但我建议避免这种做法,这是解决方法。
【讨论】:
MVVM 解决方案:
将ComboBox 的ItemsSource 和SelectedItem 属性绑定到您的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,你可以添加使用这个:
<ComboBox SelectionChanged="ComboBox_SelectionChanged" />
并在 MainWindow.xaml.cs 中添加:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Some logic here
}
【讨论】:
MySelectedItem 更改值时。如果您想改用事件处理程序,我已经用事件处理程序更新了我的答案。
您的 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}"/>
【讨论】:
i:Interaction.Triggers 相同。
我非常喜欢这种方法。
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>
【讨论】:
只是对上面存在的 solution 的增强,如果您使用的是 Prism 库
(如果没有,请立即停止阅读,没有什么适合您的)
我真的很喜欢这个解决方案,我认为它比任何其他解决方案都好,我只想对 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>,则e参数为null
如果您使用<prism:InvokeCommandAction>,则e 参数为NOT null
【讨论】: