我是C#和WPF的新手,我正在制作一个小应用程序,我认为这是学习和使用MVVM模式的好机会。
这肯定让事情变得比我想要的小应用程序更困难,但这是一个很好的学习经历。到目前为止,我已经能够跟进了。我似乎完全迷失了如何正确实现ViewModels相互交互的方式。
我有MainWindowView和OverlayView,我希望能够从主ViewModel在叠加视图上绘制一个矩形。我想要一种方法,只需从MainViewModel广播一个事件,让OverlayView听到它并按照指定绘制矩形。我也认为一旦我开始工作就添加'CloseAllWindows'广播会很方便。
从我的研究中,最简单的方法是使用像Prism这样的框架。我一直在尝试从Prism框架中建立一个Event Aggregator,但无论我尝试什么,我都无法让它工作。我看了很多文章或教程,但它们似乎都已经过时,链接断了,或者我似乎无法理解它们并让它们发挥作用。
这是我到目前为止所得到的:
Events.cs :
2018-03-19 18:24:28.079 python[84266:4693971] _createMenuRef called with existing principal MenuRef already associated with menu
2018-03-19 18:24:28.081 python[84266:4693971] (
0 CoreFoundation 0x00007fff8b693452 __exceptionPreprocess + 178
1 libobjc.A.dylib 0x00007fff9e6d073c objc_exception_throw + 48
2 CoreFoundation 0x00007fff8b6fa49d +[NSException raise:format:] + 205
3 AppKit 0x00007fff9ebf0c86 -[NSCarbonMenuImpl _createMenuRef] + 62
4 AppKit 0x00007fff9ebf05c5 -[NSCarbonMenuImpl _instantiateCarbonMenu] + 140
5 AppKit 0x00007fff9ebee270 -[NSApplication finishLaunching] + 856
6 AppKit 0x00007fff9ebedbbd -[NSApplication run] + 231
7 _macosx.so 0x0000000106e451c8 show + 216
8 libpython3.5m.dylib 0x00000001000bd34e PyEval_EvalFrameEx + 22542
9 libpython3.5m.dylib 0x00000001000c192f fast_function + 207
10 libpython3.5m.dylib 0x00000001000bd434 PyEval_EvalFrameEx + 22772
11 libpython3.5m.dylib 0x00000001000c10c3 _PyEval_EvalCodeWithName + 1779
12 libpython3.5m.dylib 0x00000001000b7b1e PyEval_EvalCodeEx + 78
13 libpython3.5m.dylib 0x000000010003430f function_call + 351
14 libpython3.5m.dylib 0x000000010000fd73 PyObject_Call + 99
15 libpython3.5m.dylib 0x000000010002130d method_call + 141
16 libpython3.5m.dylib 0x000000010000fd73 PyObject_Call + 99
17 libpython3.5m.dylib 0x0000000100064c55 slot_tp_call + 117
18 libpython3.5m.dylib 0x000000010000fd73 PyObject_Call + 99
19 libpython3.5m.dylib 0x00000001000bdec8 PyEval_EvalFrameEx + 25480
20 libpython3.5m.dylib 0x00000001000c10c3 _PyEval_EvalCodeWithName + 1779
21 libpython3.5m.dylib 0x00000001000c19ae fast_function + 334
22 libpython3.5m.dylib 0x00000001000bd434 PyEval_EvalFrameEx + 22772
23 libpython3.5m.dylib 0x00000001000c10c3 _PyEval_EvalCodeWithName + 1779
24 libpython3.5m.dylib 0x00000001000b7ac1 PyEval_EvalCode + 81
25 libpython3.5m.dylib 0x00000001000e6937 PyRun_FileExFlags + 215
26 libpython3.5m.dylib 0x00000001000e60ea PyRun_SimpleFileExFlags + 842
27 libpython3.5m.dylib 0x00000001000fcc5b Py_Main + 3355
28 python 0x0000000100000dc7 main + 215
29 python 0x0000000100000ce4 start + 52
30 ??? 0x0000000000000002 0x0 + 2
)
MainWindowViewModel.cs
using System.Windows;
using Prism.Events;
namespace Application.Overlay {
public class DrawRectEvent : PubSubEvent<Rect> {
}
}
MainWindow.xaml.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);
}
}
OverlayViewModel.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);
}
OverlayView.xaml.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!");
}
使用这段代码编译得很好,但我得到一个“Null引用异常”“对象引用没有设置为对象的in`stance”运行它时,它指的是OverlayViewModel中的第9行:
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);
}
我不确定我是否将正确的内容传递给代码隐藏中的新ViewModel实例,但我不确定你还传递了什么。
如果你看到我做错了什么或者你有一个最新的指南,显示出比我正在做的更有效的方式,那么我真的很感激。谢谢!
答案 0 :(得分:0)
由于您刚刚开始,我不会过于深入地解释基础知识,我将直接跳到'我们如何让您的当前代码构建和工作'的部分,你可以继续学习。
从我提供的代码中我可以看出,看起来你从未真正创建过EventAggregator
的实例(除非你设置了一个IoC容器,我看不到任何迹象表明你已经完成了这一点。
所以在你的代码::
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);
}