如何在WPF/MVVM应用程序的ViewModel中实现路由事件的注册

j2qf4p5b  于 2023-08-07  发布在  其他
关注(0)|答案(2)|浏览(176)

在一个新的WPF/MVVM应用程序上工作时,我“发现”了路由事件,并认为这可能对不同类之间的通信很有用。在我的示例中,一些自定义数据位于名为MainWindowViewModel的ViewModel中,当关闭应用程序时,应该保存这些数据。设法在MainWindow.xaml.cs中定义了一个新的自定义RoutedEvent,以及在用户关闭应用程序时引发它的方法。
但是,在MainWindowViewModel中找不到注册此事件的正确方法。GetRoutedEvents()向我显示(在调试模式下)我的自定义事件在那里!
有没有一种方法可以在代码中做到这一点,或者我在这里走错了路?

<Window x:Class="RoutedEventA.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vws="clr-namespace:RoutedEventA.Views"
    xmlns:vms="clr-namespace:RoutedEventA.ViewModels"
    mc:Ignorable="d"
    Closing="Window_Closing"
    Title="MainWindow" Height="200" Width="400">

<Window.DataContext>
    <vms:MainWindowViewModel />
</Window.DataContext>

<Grid>
    <vws:MainWindowView/>
</Grid>

个字符

bvuwiixz

bvuwiixz1#

简短的答案很简单:你不能这么做
详细的答案非常明确:正如我之前所说的,你不能直接从视图到视图模型注册事件,但是你可以使用一个nuget包来解决这个问题。首先,在项目中引用 *Microsoft.Xaml.Behaviors.Wpf * 包:https://www.nuget.org/packages/Microsoft.Xaml.Behaviors.Wpf
然后,在您的窗口中引用它

<Window x:Class="RoutedEventA.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vws="clr-namespace:RoutedEventA.Views"
    xmlns:vms="clr-namespace:RoutedEventA.ViewModels"
    xmlns:behavior="http://schemas.microsoft.com/xaml/behaviors"
    mc:Ignorable="d"
    Title="MainWindow" Height="200" Width="400">

    <Window.DataContext>
        <vms:MainWindowViewModel />
    </Window.DataContext>

    <Grid>
        <vws:MainWindowView/>
    </Grid>

字符串
因此,在视图模型中创建一个适当的ICommand来处理事件引发并将事件绑定到它(由于篇幅的原因,我不会解释如何做到这一点,但您可以在此链接中找到所需的所有信息:ICommand MVVM implementation

<Window x:Class="RoutedEventA.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vws="clr-namespace:RoutedEventA.Views"
    xmlns:vms="clr-namespace:RoutedEventA.ViewModels"
    xmlns:behavior="http://schemas.microsoft.com/xaml/behaviors"
    mc:Ignorable="d"
    Title="MainWindow" Height="200" Width="400">

<Window.DataContext>
    <vms:MainWindowViewModel />
</Window.DataContext>

<behavior:Interaction.Triggers>
    <behavior:EventTrigger EventName="Closing">
        <behavior:InvokeCommandAction Command="{Binding WindowClosingCommand}" />
    </behavior:EventTrigger>
</behavior:Interaction.Triggers>
<Grid>
    <vws:MainWindowView/>
</Grid>

dz6r00yl

dz6r00yl2#

WPF事件通常用于将UI控件引发的事件连接到代码隐藏文件中的事件处理程序。
我认为您的案例更像是一个应用程序事件,它可以在任何地方使用,而不仅仅是在文件后面的代码中使用。

WPF的棱镜-事件聚合器

也许你应该看看“Prism for WPF”库,参见Prism for WPF
您可以使用一个名为“事件聚合器”的功能。这使您能够使用IEventAggregator接口发布事件和订阅事件。您可以在程式码中的任何地方执行这项作业。发布事件的类和处理事件的类不需要彼此知道。
下面的示例代码取自此处:https://prismlibrary.com/docs/event-aggregator.html
定义一个保存事件数据的数据类。此类派生自PRISMS PubSubEvent<T> class,并可定义其他属性:

public class TickerSymbolSelectedEvent : PubSubEvent<string>{}

字符串
提供IEventAggregator型别的执行严修给想要订阅事件的类别。请使用IEventAggregators GetEvent方法取得事件的指涉。然后附加一个事件处理方法(本例中为ShowNews):

public class MainPageViewModel
    {
        public MainPageViewModel(IEventAggregator ea)
        {
            ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews);
        }
    
        void ShowNews(string companySymbol)
        {
            //implement logic
        }
    }


现在介绍如何发布事件(在另一个类中)。这与订阅事件几乎相同。但是,在IEventAggregator中使用的不是Subscribe,而是Publish方法:

public class SomeOtherClass
{
    IEventAggregator _eventAggregator;
    public MainPageViewModel(IEventAggregator ea)
    {
        _eventAggregator = ea;
    }

    public void CreateAndPublishEvent()
    {
        _eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish("STOCK0");
    }
}


最后,在应用程序的启动逻辑中的某个位置创建一个EventAggregator示例,例如在App.xaml.cs文件中。然后,以某种方式将其传递给viewmodel和其他想要使用它的类。始终传递同一示例!

EventAggregator ea = new EventAggregator(); // implements IEventAggregator
    MainPageViewModel viewModel = new MainPageViewModel(ea);

相关问题