将数据从 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 是您的数据源?

好的,这里是一个关于如何设置 AppBotstraperEventAggregator 的小例子。

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 否则你会得到一个错误。