将数据从 window 传回 ShellViewModel
Passing data from a window back to ShellViewModel
好的,我在解决这个问题时遇到了问题。我发现的大多数教程要么不完整,要么没有很好地解释这个过程。
我用 Caliburn.Micro 创建了一个测试 WPF 应用程序,该应用程序的主要 window (ShellViewModel) 有一个文本框和一个按钮,该按钮打开第二个 window 文本框和另一个按钮。当用户在第二个 window 中添加文本并单击 "send" 时,将创建 POCO 对象并应将其发送到第一个 window 并显示在 ShellViewModel 的文本框中。
我不确定哪里出错了,似乎没有很多文章可以帮助解决这个问题。
我尝试使用以下文章寻求帮助:
https://claytonone.wordpress.com/2014/06/14/caliburn-micro-part-1-getting-started/
https://caliburnmicro.com/documentation/event-aggregator
******编辑 - 按照中的说明重新编程上述项目
https://caliburnmicro.com/documentation/event-aggregator
下面是这个项目的代码。注意我添加了一个 POCO class 来存储和发送我想发送的数据到另一个 window,这更多是我在我正在从事的主要项目中的最终目标。
我现在 运行 遇到的问题:
1. 当我运行根据教程设计程序时,VS Errored 说没有无参数构造函数。为此,我尝试添加构造函数。现在的程序 运行。
2. 当我在第二个 window 中键入文本并单击发送时,我得到一个 "Null Reference Error",但如果我调试 "ToSend" 对象,则会创建并填充正确的数据。
AppBootStrapper:
namespace CaliburnMicro
{
class AppBootstrapper : BootstrapperBase
{
private readonly SimpleContainer _container = new SimpleContainer();
public AppBootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override void Configure()
{
_container.Singleton<IEventAggregator, EventAggregator>();
}
}
}
ShellViewModel:
namespace CaliburnMicro.ViewModels
{
class ShellViewModel : Screen, IHandle<EventMessage>
{
private string _messageBox;
private readonly IEventAggregator _eventAggregator;
public string MessageBox
{
get { return _messageBox; }
set
{
_messageBox = value;
NotifyOfPropertyChange(() => MessageBox);
}
}
public ShellViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
}
public ShellViewModel()
{
}
public void OpenWindow()
{
WindowManager wm = new WindowManager();
SecondWindowViewModel swm = new SecondWindowViewModel(_eventAggregator);
wm.ShowWindow(swm);
}
public void Handle(EventMessage message)
{
MessageBox = message.Text;
}
}
}
第二个WindowViewModel
namespace CaliburnMicro.ViewModels
{
class SecondWindowViewModel: Screen
{
private string _secondTextBox;
private readonly IEventAggregator _eventAggregator;
public EventMessage Tosend = new EventMessage();
public string SecondTextBox
{
get { return _secondTextBox; }
set
{
_secondTextBox = value;
NotifyOfPropertyChange(() => SecondTextBox);
}
}
public SecondWindowViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public void SendBack()
{
Tosend.Text = SecondTextBox;
_eventAggregator.PublishOnUIThread(Tosend);
Thread.Sleep(1000); //I wanted the app to wait a second before closing
TryClose();
}
}
}
这是我要从第二发回主 window 的 POCO。
namespace CaliburnMicro.Models
{
class EventMessage
{
public string Text { get; set; }
}
}
想一想,您是否设置了 DataContext
以便您的主要 window 知道 ViewModel 是您的数据源?
好的,这里是一个关于如何设置 AppBotstraper
和 EventAggregator
的小例子。
AppBootstrapper.cs
public class AppBootstrapper : BootstrapperBase
{
private SimpleContainer _container;
public AppBootstrapper()
{
Initialize();
}
protected override void Configure()
{
_container = new SimpleContainer();
_container.Singleton<IWindowManager, WindowManager>();
_container.Singleton<IEventAggregator, EventAggregator>();
_container.PerRequest<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
}
ShellViewModel.cs
public class ShellViewModel : Screen, IScreen, IHandle<EventMessage>
{
private readonly IEventAggregator _eventAggregator;
public ShellViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
}
public void OpenWindow()
{
WindowManager wm = new WindowManager();
SecondWindowViewModel swm = new SecondWindowViewModel(_eventAggregator);
wm.ShowWindow(swm);
}
public void Handle(EventMessage message)
{
MessageBox.Show(message.Text);
}
}
注意:如果您不了解 Caliburn.Micro
中的导体,我建议您阅读 this。当您使用导体时,您可以使用方法 ActivateItem
.
在 UserControl
中启动任何子 ViewModel
你的 SecondWindowViewModel
保持不变,但是 EventMessage
class 必须是 public class EventMessage
否则你会得到一个错误。
好的,我在解决这个问题时遇到了问题。我发现的大多数教程要么不完整,要么没有很好地解释这个过程。
我用 Caliburn.Micro 创建了一个测试 WPF 应用程序,该应用程序的主要 window (ShellViewModel) 有一个文本框和一个按钮,该按钮打开第二个 window 文本框和另一个按钮。当用户在第二个 window 中添加文本并单击 "send" 时,将创建 POCO 对象并应将其发送到第一个 window 并显示在 ShellViewModel 的文本框中。
我不确定哪里出错了,似乎没有很多文章可以帮助解决这个问题。
我尝试使用以下文章寻求帮助: https://claytonone.wordpress.com/2014/06/14/caliburn-micro-part-1-getting-started/
https://caliburnmicro.com/documentation/event-aggregator
******编辑 - 按照中的说明重新编程上述项目 https://caliburnmicro.com/documentation/event-aggregator 下面是这个项目的代码。注意我添加了一个 POCO class 来存储和发送我想发送的数据到另一个 window,这更多是我在我正在从事的主要项目中的最终目标。
我现在 运行 遇到的问题:
1. 当我运行根据教程设计程序时,VS Errored 说没有无参数构造函数。为此,我尝试添加构造函数。现在的程序 运行。
2. 当我在第二个 window 中键入文本并单击发送时,我得到一个 "Null Reference Error",但如果我调试 "ToSend" 对象,则会创建并填充正确的数据。
AppBootStrapper:
namespace CaliburnMicro
{
class AppBootstrapper : BootstrapperBase
{
private readonly SimpleContainer _container = new SimpleContainer();
public AppBootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override void Configure()
{
_container.Singleton<IEventAggregator, EventAggregator>();
}
}
}
ShellViewModel:
namespace CaliburnMicro.ViewModels
{
class ShellViewModel : Screen, IHandle<EventMessage>
{
private string _messageBox;
private readonly IEventAggregator _eventAggregator;
public string MessageBox
{
get { return _messageBox; }
set
{
_messageBox = value;
NotifyOfPropertyChange(() => MessageBox);
}
}
public ShellViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
}
public ShellViewModel()
{
}
public void OpenWindow()
{
WindowManager wm = new WindowManager();
SecondWindowViewModel swm = new SecondWindowViewModel(_eventAggregator);
wm.ShowWindow(swm);
}
public void Handle(EventMessage message)
{
MessageBox = message.Text;
}
}
}
第二个WindowViewModel
namespace CaliburnMicro.ViewModels
{
class SecondWindowViewModel: Screen
{
private string _secondTextBox;
private readonly IEventAggregator _eventAggregator;
public EventMessage Tosend = new EventMessage();
public string SecondTextBox
{
get { return _secondTextBox; }
set
{
_secondTextBox = value;
NotifyOfPropertyChange(() => SecondTextBox);
}
}
public SecondWindowViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public void SendBack()
{
Tosend.Text = SecondTextBox;
_eventAggregator.PublishOnUIThread(Tosend);
Thread.Sleep(1000); //I wanted the app to wait a second before closing
TryClose();
}
}
}
这是我要从第二发回主 window 的 POCO。
namespace CaliburnMicro.Models
{
class EventMessage
{
public string Text { get; set; }
}
}
想一想,您是否设置了 DataContext
以便您的主要 window 知道 ViewModel 是您的数据源?
好的,这里是一个关于如何设置 AppBotstraper
和 EventAggregator
的小例子。
AppBootstrapper.cs
public class AppBootstrapper : BootstrapperBase
{
private SimpleContainer _container;
public AppBootstrapper()
{
Initialize();
}
protected override void Configure()
{
_container = new SimpleContainer();
_container.Singleton<IWindowManager, WindowManager>();
_container.Singleton<IEventAggregator, EventAggregator>();
_container.PerRequest<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
}
ShellViewModel.cs
public class ShellViewModel : Screen, IScreen, IHandle<EventMessage>
{
private readonly IEventAggregator _eventAggregator;
public ShellViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
}
public void OpenWindow()
{
WindowManager wm = new WindowManager();
SecondWindowViewModel swm = new SecondWindowViewModel(_eventAggregator);
wm.ShowWindow(swm);
}
public void Handle(EventMessage message)
{
MessageBox.Show(message.Text);
}
}
注意:如果您不了解 Caliburn.Micro
中的导体,我建议您阅读 this。当您使用导体时,您可以使用方法 ActivateItem
.
UserControl
中启动任何子 ViewModel
你的 SecondWindowViewModel
保持不变,但是 EventMessage
class 必须是 public class EventMessage
否则你会得到一个错误。