WPF Caliburn.Micro - 最佳的方式在辛格窗口应用程序导航

WPF Caliburn.Micro - 最佳的方式在辛格窗口应用程序导航

问题描述:

  1. 我的历史:

我正在开发一个WPF应用程序,这将在全屏幕触摸屏上运行。在我的应用程序中导航只能通过点击每个页面上的按钮来完成(“返回”或“注销”)。WPF Caliburn.Micro - 最佳的方式在辛格窗口应用程序导航

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

  1. 假设项目:

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

  3. 我有1个窗和3用户控件(和的ViewModels)Concept art

    Window ShellView 
        UserControl LoginView 
        UserControl OrdersView 
        UserControl OrderDetailView 
    

    当应用程序开始,我设定LoginView为默认并通过使用CM Conductor ActivateItem方法加载它,但我不知道如何从UserControl设置另一个视图,如LoginView

    我已阅读:this question但这并不包括我的情况 和this answer但我很难理解。

    我的想法:

  • 使静态方法ShellViewModel,如:

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(); 
  • 化妆监听器,并从子视图模型发送事件(但现在我不知道如何实现它)

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

  1. 应用架构:
  2. ShellView

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

    ShellViewModel

    public class ShellViewModel : Conductor<object>, IShell 
    { 
    
        public ShellViewModel() 
        { 
         LoadDefault(); 
        }  
    
        public void LoadDefault() 
        { 
         ActivateItem(new LoginViewModel()); 
        } 
    } 
    

    LoginView

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

    LoginViewModel

    public class LoginViewModel : PropertyChangedBase 
    { 
        public void Login() { 
         if (LoginManager.Login("User", "Password")) { 
          // How to redirect user to OrdersView? 
         } 
        } 
    } 
    
开始=> 开始=>

我有一个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需要在实施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; 
    } 
} 

所有您的viewModels也可以订阅EventAggregator实例和Ha发送一些用于通信的消息,甚至用于初始参数。我几乎对每个viewModel都有类似MyViewModelInitMessage的类,并且只是一起使用两个发布方法。

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

所以,当我出版这两个 - 矿ViewModel就会被激活,那么订阅EventAggregator不要忘了做,或者第二个消息处理永远不会发生),并且将处理其InitMessage右后。

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

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