65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ViewModel 中处理 UI 控件的事件

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.38/5 (5投票s)

2014 年 11 月 17 日

CPOL

3分钟阅读

viewsIcon

22582

本技巧将讨论如何在 MVVM 结构中处理与 UI 控件相关的事件。

引言

最近,我遇到了一个需求,需要将一个命令从我的 viewModel 数据绑定到一个事件。换句话说,我的代码隐藏不应该包含任何与控件的事件处理程序相关的代码。

在深入研究 Prism 之后,幸运的是我找到了答案。上述需求可以使用 Prism 5.0 中提供的 InvokeCommandAction 来实现。

好吧,所以我的文章将更详细地阐述如何实现这一点。

InvokeCommandAction

InvokeCommandAction 允许我们在我们的 viewModel 上调用 ICommand 实现,以响应我们的控件上的一个事件。 基本上这意味着,我们不再受限于在控件上拥有一个命令属性才能调用命令。

现在,您可能会说您之前见过类似的东西。

您是对的,因为 Blend SDK 就自带一个。但是 Prism 提供的 InvokeCommandAction 在两个方面略有不同

  • 首先,它管理元素的的状态。它根据命令 CanExecute 的返回值更新所附加控件的启用状态。所以,在这里你得到了与任何控件相同的行为,这非常酷。不是吗?
  • 其次,它允许我们将事件参数作为参数传递给命令。

现在有人可能会问一个问题,我们是否必须将整个 EventArgs 作为参数传递,或者我们是否可以只传递所需的内容?

答案是肯定的。当然,您不必将整个 EventArgs 传递给您的 viewModel。 也可以传递 EventArgs 的一部分,这是真正需要的。 这可以通过在 InvokeCommandAction 上设置 TriggerPathParameter 来实现。

让我们快速跳转到代码。

使用代码

为了解释 InvokeCommandAction 的概念,我将创建一个非常简单的应用程序,该应用程序包含一个 ListBox 和一个 LabelLabel 将根据列表中选定的项目进行更新。

期望:每当在列表中选择一个项目时,我们都必须侦听 SelectionChanged 事件,然后在 viewModel 中通过命令处理该事件,然后更新 Label 上选定的文本项。

设置视图

<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
      <ListBox Height="100" Width="300" Margin="1,20,0,0" 
          ItemsSource="{Binding ListOfItems}" SelectionMode="Single"/>
      <LabelFontWeight="Bold" Width="170" 
      Height="30" Content="Please select"/>
</StackPanel>

我在代码隐藏中为这个视图设置数据上下文。但同样的事情也可以在 XAML 中完成。

设置 ViewModel

在这里,我不会解释 viewModel 代码的每一行,因为我已经在我 其他 的文章中以详细的方式涵盖了相同的内容。

public class MainWindowViewModel:BindableBase
    {
        public ObservableCollection<string> ListOfItems { get; set; }
        public ICommand SelectCommand { get; set; }

        private string _selectedItem = string.Empty;
        public string SelectedItem
        {
            get { return _selectedItem; }
            set { SetProperty<string>(ref _selectedItem, value); }
        }

        public MainWindowViewModel()
        {
            ListOfItems = new ObservableCollection<string>() 
            {"One","Two", "Three", "Four", "Five"};
            SelectCommand = new DelegateCommand<object[]>(SetSelectedItem);           
        }

        private void SetSelectedItem(object[] listOfItems)
        {
            if (listOfItems != null && listOfItems.Count()>0)
            {
                 SelectedItem=listOfItems.FirstOrDefault().ToString();
            }
        }
    }

如果您注意到 DelegateCommand 的参数,它是一个对象数组。那是因为我们的 viewModel 将期望一个命令操作,该操作以我们想要从中选择的项目的列表中的对象数组的形式出现。

接下来要做的是处理我们的 ListBox SelectionChanged 事件,但我们不想在我们的代码隐藏中处理它,因为我们正在处理 MVVM 结构。因此,为了实现此行为,我们将使用触发器。

让我们继续添加 System.Windows.Interactivity 的引用,并在 XAML 中添加命名空间,如下所示

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

现在,上述命名空间可用于将交互触发器附加到附加属性,如下所示

<ListBox Height="100" Width="300" 
Margin="1,20,0,0" ItemsSource="{Binding ListOfItems}" 
    SelectionMode="Single">
<interactivity:Interaction.Triggers>
        ...
 </interactivity:Interaction.Triggers>
</ListBox>

接下来,我们需要添加 EventTrigger ,并将 EventName 属性设置为 SelectionChanged。 请注意,您的 EventName 应该与控件的事件匹配。 在这种情况下,我们对 ListBoxSelectionChanged 事件感兴趣。

现在,每当发生此事件时,我们都希望调用我们的命令。 所以,这就是我们使用 Prism 的 InvokeCommandAction 的地方

<ListBox Height="100" Width="300" 
Margin="1,20,0,0" ItemsSource="{Binding ListOfItems}" 
    SelectionMode="Single">
    <interactivity:Interaction.Triggers>
        <interactivity:EventTrigger EventName="SelectionChanged">
              <prism:InvokeCommandAction Command="{Binding SelectCommand}"/>
        </interactivity:EventTrigger>
    </interactivity:Interaction.Triggers>
</ListBox>

让我们快速运行该应用程序,看看它的反应。

当您尝试在 ListBox 中选择任何项目时,您将收到一个 BIG 异常

看起来传递给命令的参数是 SelectionChangedEventArgs。 我们不想要那个。 我们想要一些特定的东西,我们想要我们的对象。 所以,让我们回到我们的 InvokeCommandAction 并设置属性 TriggerParamaterPath ,其中包含触发器的传入 EventArgs 的路径。 在我们的例子中,我们想要 AddedItems。 因此,

 <ListBox Height="100" Width="300" 
Margin="1,20,0,0" ItemsSource="{Binding ListOfItems}" 
    SelectionMode="Single">
       <interactivity:Interaction.Triggers>
           <interactivity:EventTrigger EventName="SelectionChanged">
                  <prism:InvokeCommandAction Command="{Binding SelectCommand}" 
            TriggerParameterPath="AddedItems"/>
           </interactivity:EventTrigger>
       </interactivity:Interaction.Triggers>
 </ListBox>

现在,当您运行应用程序时,您将获得预期的输出。

希望您喜欢学习!!!

© . All rights reserved.