繁体   English   中英

如何在ViewModel之间进行通信? (棱镜事件聚合器?)

[英]How to communicate between ViewModels? ( Prism event aggregator?)

我是C#和WPF的新手,我正在制作一个小型应用程序,所以我认为这是学习和使用MVVM模式的好机会。

这肯定使事情比我对小型应用程序的预期要困难一些,但这是一种很好的学习体验。 到目前为止,我一直可以跟进。 我似乎完全不知道如何正确实现ViewModels彼此交互的方式。

我有MainWindowView和OverlayView,我希望能够从主ViewModel在覆盖视图上绘制一个矩形。 我想要一种方法,能够从MainViewModel广播事件,并让OverlayView听到它并按指定方式绘制矩形。 我还认为,一旦工作正常,添加“ CloseAllWindows”广播会很方便。

根据我的研究,最简单的方法是使用Prism这样的框架。 我一直在尝试从Prism框架设置一个Event Aggregator,但是无论我如何尝试,我都无法使其正常工作。 我到处都在寻找文章或教程,但它们似乎都已过时,链接断开,或者我似乎无法理解它们并使它们正常工作。

这是到目前为止我得到的:

Events.cs

using System.Windows;
using Prism.Events;

namespace Application.Overlay {
    public class DrawRectEvent : PubSubEvent<Rect> {
    }
}

MainWindowViewModel.cs

 namespace Application.ViewModels {

    public class MainWindowViewModel : BindableBase {

        private IEventAggregator eventAggregator;

        public MainWindowViewModel(IEventAggregator eventAggregator) {
            this.eventAggregator = eventAggregator;

            WindowLoadedCommand = new RelayCommand(WindowLoaded);
            TestDrawCommand = new RelayCommand(TestDraw);
        }

        public RelayCommand TestDrawCommand { get; set; }
        public void TestDraw() {
            Console.WriteLine("Publishing DrawRect Broadcast");
            Size size = new Size(100, 100);
            Point point = new Point(50, 50);
            Rect rect = new Rect(point, size);

            eventAggregator.GetEvent<DrawRectEvent>().Publish(rect);
        }
}

MainWindow.xaml.cs

namespace Application {

    public partial class MainWindow : Window {
        private IEventAggregator eventAggregator;
        TextBoxOutputter outputter;

        public MainWindow() {
            this.DataContext = new ViewModels.MainWindowViewModel(eventAggregator);
            InitializeComponent();

        // Route console output to ConsoleOutput TextBox
        outputter = new TextBoxOutputter(ConsoleOutput);
        Console.SetOut(outputter);
    }

OverlayViewModel.cs

namespace Application.Overlay : BindableBase {

    public class OverlayViewModel {
    private IEventAggregator eventAggregator;

    public OverlayViewModel(IEventAggregator eventAggregator) {

        this.eventAggregator = eventAggregator;
        this.eventAggregator.GetEvent<DrawRectEvent>().Subscribe(DrawRectEventHandler);
        }

        private void DrawRectEventHandler(Rect rect) {
            Console.WriteLine("Signal Received, Drawing Rectangle!");
        }

OverlayView.xaml.cs

namespace Application.Overlay {

    public partial class Overlay : Window {

        private IEventAggregator eventAggregator;

        public Overlay() {
            InitializeComponent();
            Top = 0;
            Left = 0;
            this.Height = System.Windows.SystemParameters.PrimaryScreenHeight;
            this.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
            this.WindowStyle = WindowStyle.None;

            this.DataContext = new OverlayViewModel(eventAggregator);
        }

使用此代码,它可以很好地编译,但是在运行它时会收到“空引用异常”“对象引用未设置为对象的实例”,它引用了OverlayViewModel中的第9行:

this.eventAggregator.GetEvent<DrawRectEvent>().Subscribe(DrawRectEventHandler);

我不确定是否要在后面的代码中将正确的东西传递给新的ViewModel实例,但是我不确定您还会传递什么。

如果您发现我做错了什么,或者您有一份最新指南显示了比我做的事更有效的方法,那么我将不胜感激。 谢谢!

既然您才刚刚起步,我就不会花太多时间解释基础知识,我将直接跳到“如何使您的当前代码得以构建和运行”这一部分,您可以继续前进在学习上。

据我提供的代码可以看出,您似乎从未真正创建过EventAggregator的实例(除非您已经设置了IoC容器,但我看不到任何表明您拥有已经做到了)。

所以在你的代码中:

MainWindow.xaml.cs

public partial class MainWindow : Window {
    private IEventAggregator eventAggregator;
    TextBoxOutputter outputter;

    public MainWindow() {
        this.DataContext = new ViewModels.MainWindowViewModel(eventAggregator);
        InitializeComponent();

    // Route console output to ConsoleOutput TextBox
    outputter = new TextBoxOutputter(ConsoleOutput);
    Console.SetOut(outputter);
}

您正在创建ViewModels.MainWindowViewModel的实例,并传递空字段eventAggregator 在此之前,您需要使用实际实例填充该字段。 所以试试这个:

public partial class MainWindow : Window {
    private IEventAggregator eventAggregator;
    TextBoxOutputter outputter;

    public MainWindow() {
        this.eventAggregator = new EventAggregator(); //<---
        this.DataContext = new ViewModels.MainWindowViewModel(eventAggregator);
        InitializeComponent();

    // Route console output to ConsoleOutput TextBox
    outputter = new TextBoxOutputter(ConsoleOutput);
    Console.SetOut(outputter);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM