WPF Caliburn.Micro - 单窗口应用程序中最佳的导航方式

4
  1. 我的历史:

我正在开发一款WPF应用程序,将在触摸屏上全屏运行。在我的应用程序中,导航只能通过每个页面上的按钮(“返回”或“注销”)来完成。

这不是通用应用程序,但它看起来像。

  1. 项目假设:

    • 应用程序将在Windows 7上的触摸屏上以全屏模式运行。
    • 我正在使用Caliburn.Micro MVVM框架。
  2. 问题和疑问:

我有1个窗口和3个UserControl(以及ViewModels)概念艺术

 Window ShellView
     UserControl LoginView
     UserControl OrdersView
     UserControl OrderDetailView

当应用程序启动时,我将LoginView设置为默认视图,并使用CM Conductor ActivateItem方法加载它,但我不知道如何从UserControl设置另一个视图,例如LoginView。
我已经阅读了this question,但这并不涵盖我的情况,以及this answer,但对我来说太难理解了。
我的想法是:
在ShellViewModel中创建静态方法,例如:
ShellViewModel
public static void setOrdersView() {
    ActivateItem(new OrdersViewModel());
    // Error : An object reference is required for the non-static field, method, or property 'Caliburn.Micro.ConductorBase<object>.ActivateItem(object)
}
ShellViewModel.setOrdersView();
  • 在ShellViewModel中创建监听器并从子ViewModel发送事件(但现在我不知道如何实现)

问题:在这种情况下处理导航的最佳方法是什么?

  1. 应用程序架构:

ShellView

<Window>
   <ContentControl x:Name="ActiveItem" />
</Window>

ShellViewModel
public class ShellViewModel : Conductor<object>, IShell
{

    public ShellViewModel()
    {
        LoadDefault();
    }    

    public void LoadDefault()
    {
        ActivateItem(new LoginViewModel());
    }
}

登录视图

<UserControl>
    <Button x:Name="Login" />
</UserControl>

登录视图模型

public class LoginViewModel : PropertyChangedBase
{
    public void Login() {
        if (LoginManager.Login("User", "Password")) {
            // How to redirect user to OrdersView?
        }
    }
}
1个回答

6

我有类似的应用程序,其中有一个外壳窗口和许多已激活的视图以及一些对话框窗口。

针对这些需求,您应该使用EventAggregator模式,并且Caliburn已经有了实现。

如何实现:

最小Shell签名

public class ShellViewModel : Conductor<object>,
    IHandle<ChangePageMessage>,
    IHandle<OpenWindowMessage>

您需要在内部使用两个字段(第二个用于对话框):

public IEventAggregator EventAggregator { get; private set; }
public IWindowManager WindowManager { get; private set; }

我已经通过IoC设置了这些对象的单个实例。您也可以将它们定义为Singletons。 EventAggregator需要在实现IHandle的对象上进行订阅。

EventAggregator.Subscribe(this); //You should Unsubscribe when message handling is no longer needed

处理程序实现:

public void Handle(ChangePageMessage message) {
    var instance = IoC.GetInstance(message.ViewModelType, null);//Or just create viewModel by type
    ActivateItem(instance);
}

public void Handle(OpenWindowMessage message) {
    var instance = IoC.GetInstance(message.ViewModelType, null);//Or just create viewModel by type
    WindowManager.ShowWindow(instance);
}

事件聚合器的消息可以只是标记类,但有时传递更多参数是很有用的,例如我们的OpenWindowMessageChangePageMessage类-它们在内容上完全相似,因此例如:

public class OpenWindowMessage {

    public readonly Type ViewModelType;

    public OpenWindowMessage(Type viewModelType) {
        ViewModelType = viewModelType;
    }
}

您的所有视图模型也可以订阅事件聚合器实例并处理一些消息以进行通信,甚至用于初始参数。我有类似于MyViewModelInitMessage的类几乎适用于每个视图模型,并只使用两种发布方法。

EventAggregator.Publish(new ChangePageMessage(typeof(MyViewModel)));
EventAggregator.Publish(new MyViewModelInitMessage("...all needed parameters"));

所以当我发布这两个 - 我的ViewModel将被激活,然后它订阅EventAggregator(不要忘记这样做,否则第二条消息处理永远不会发生),并且将立即处理其InitMessage

现在,使用EventAggregator,您可以在所有当前订阅它的ViewModel之间发送消息。

这似乎是相当常见的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接