【问题标题】:WPF Caliburn.Micro - Best way to navigate in Singe Window ApplicationWPF Caliburn.Micro - 在单窗口应用程序中导航的最佳方式
【发布时间】:2015-05-14 12:41:25
【问题描述】:
  1. 我的历史:

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

这不是通用应用,但看起来很像。

  1. 项目假设:

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

我有 1 个窗口和 3 个 UserControl(和 ViewModels)Concept art

 Window ShellView
     UserControl LoginView
     UserControl OrdersView
     UserControl OrderDetailView

当应用程序启动时,我将 LoginView 设置为默认值并使用 CM Conductor ActivateItem 方法加载它,但我不知道如何从 UserControl 设置另一个 View,如 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. 应用架构:

外壳视图

<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?
        }
    }
}

【问题讨论】:

    标签: c# wpf mvvm caliburn.micro


    【解决方案1】:

    我有类似的应用程序,只有一个 shell 窗口,里面有许多激活的视图和一些对话框窗口。 您应该使用 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 设置了该对象的单个实例。您还可以将它们定义为单例。 EventAggregator 需要订阅实现IHandles 的对象。

    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;
        }
    }
    

    您所有的 viewModel 也可以订阅 EventAggregator 实例并处理一些消息以进行通信,甚至是初始参数。我几乎为每个视图模型都有类似MyViewModelInitMessage 的类,并且只需一起使用两个发布方法。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 2023-03-07
      • 2012-08-02
      • 1970-01-01
      • 1970-01-01
      • 2012-10-07
      • 1970-01-01
      相关资源
      最近更新 更多