【问题标题】:How to handle the SelectionChanged event of ComboBox with MVVM in wpf?如何在 wpf 中使用 MVVM 处理 ComboBox 的 SelectionChanged 事件?
【发布时间】:2012-01-29 18:38:33
【问题描述】:

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

我想要的是在ComboBox 项目选择发生变化时做一些操作。如何以 MVVM 方式实现它?

【问题讨论】:

    标签: wpf mvvm wpf-controls


    【解决方案1】:

    首先让我们把事情说清楚 - 您不能更改事件,而是可以订阅。

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

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

    还有其他解决方案通过view.DataContext 访问 ViewModel 来处理 View 背后的代码,但我建议避免这种做法,这是解决方法。

    【讨论】:

      【解决方案2】:

      MVVM 解决方案

      ComboBoxItemsSourceSelectedItem 属性绑定到您的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 更改值时。如果您想改用事件处理程序,我已经用事件处理程序更新了我的答案。
      • 它运作良好.. 以及如何在 mvvm 运行时更改标签的内容。我已将值设置为分配给标签控件的属性?
      • 将 Label 的 Text 属性绑定到 ViewModel 上的字符串属性。然后只需在代码中更改该属性。绑定将更新视图。
      【解决方案3】:

      您的 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}"/> 
      

      【讨论】:

      • 虽然这是一个很好的做法,但无助于解决问题。 @Tanya 希望当用户从 UI 更改选择时通知她在视图模型中的代码,以便相应地执行一些操作。通知属性更改用于执行相反的操作。
      • @Bishoy IMO 它有帮助。如果 value != currentvalue 则选择更改。与使用 i:Interaction.Triggers 相同。
      【解决方案4】:

      我非常喜欢这种方法。

      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>
      

      【讨论】:

      • 这是我使用 MVVM 最简单的方法。谢谢!
      • 在 SelectedRegion 设置器中更容易处理并比较旧值。为什么要创建 EventTrigger?
      • @Konrad 在 ICommand 实现中封装选择更改逻辑有很多好处。特别是能够在您的 ICommand.Execute 方法中使用 async/await(尽管如果此方法返回一个 Task 会更好)。
      • @echo 是的,视情况而定。我总体上不喜欢 WPF,因为它被过度设计并且几乎已经死了 - 来自大公司的所有新应用程序都使用电子或其他东西,也许 Avalonia 更好。我现在会用某种 HTML 或 C++ 和 Qt 或 Sciter 来做所有事情;)
      • 现在我的 PC 上有 5 个或更多电子应用程序......非常消耗资源,但 UI 非常好。
      【解决方案5】:

      只是对上面存在的 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>
      }
      

      如果使用&lt;i:InvokeCommandAction&gt;,则e参数为null
      如果您使用&lt;prism:InvokeCommandAction&gt;,则e 参数为NOT null

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-17
        • 2017-07-15
        • 1970-01-01
        • 2014-05-02
        相关资源
        最近更新 更多