WPF Caliburn.Micro - 在 Singe Window 应用程序中导航的最佳方式
WPF Caliburn.Micro - Best way to navigate in Singe Window Application
- 我的历史:
我正在开发 WPF 应用程序,它将 运行 在触摸屏上全屏显示。我的应用程序中的导航只能通过单击每个页面上的按钮来完成("back" 或 "logout")。
这不是通用应用程序,但看起来像。
项目假设:
- 应用程序将 运行 在触摸屏上 Windows 7 全屏模式。
- 我正在使用 Caliburn.Micro MVVM 框架。
问题与疑问:
我有 1 个 window 和 3 个 UserControl(和 ViewModel)Concept art
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 发送事件(但现在我不知道如何实现)
问题:在这种情况下处理导航的最佳方式是什么?
- 应用架构:
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?
}
}
}
我有一个类似的应用程序,其中有一个 shell window,里面有许多激活的视图和一些对话框 windows。
您应该使用 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
s 的对象。
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);
}
事件聚合器的消息只能是标记 类,但有时传递更多参数很有用,例如我们的 OpenWindowMessage
和 ChangePageMessage
类 - 它们绝对相似按内容,例如:
public class OpenWindowMessage {
public readonly Type ViewModelType;
public OpenWindowMessage(Type viewModelType) {
ViewModelType = viewModelType;
}
}
您所有的 viewModels 也可以订阅 EventAggregator 实例并处理一些消息以进行通信,甚至是初始参数。我几乎对每个 viewModel 都有类似 MyViewModelInitMessage
类 的东西,并且只需同时使用两种发布方法。
EventAggregator.Publish(new ChangePageMessage(typeof(MyViewModel)));
EventAggregator.Publish(new MyViewModelInitMessage("...all needed parameters"));
所以当我发布这两个时 - 我的 ViewModel
将被激活,然后它订阅 EventAggregator
(不要忘记这样做,否则第二个消息处理永远不会发生),然后将立即处理它的 InitMessage
。
现在使用 EventAggregator,您可以在当前订阅它的所有 ViewModel 之间发送消息。
这似乎是很常见的解决方案。
- 我的历史:
我正在开发 WPF 应用程序,它将 运行 在触摸屏上全屏显示。我的应用程序中的导航只能通过单击每个页面上的按钮来完成("back" 或 "logout")。
这不是通用应用程序,但看起来像。
项目假设:
- 应用程序将 运行 在触摸屏上 Windows 7 全屏模式。
- 我正在使用 Caliburn.Micro MVVM 框架。
问题与疑问:
我有 1 个 window 和 3 个 UserControl(和 ViewModel)Concept art
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 发送事件(但现在我不知道如何实现)
问题:在这种情况下处理导航的最佳方式是什么?
- 应用架构:
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?
}
}
}
我有一个类似的应用程序,其中有一个 shell window,里面有许多激活的视图和一些对话框 windows。 您应该使用 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
s 的对象。
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);
}
事件聚合器的消息只能是标记 类,但有时传递更多参数很有用,例如我们的 OpenWindowMessage
和 ChangePageMessage
类 - 它们绝对相似按内容,例如:
public class OpenWindowMessage {
public readonly Type ViewModelType;
public OpenWindowMessage(Type viewModelType) {
ViewModelType = viewModelType;
}
}
您所有的 viewModels 也可以订阅 EventAggregator 实例并处理一些消息以进行通信,甚至是初始参数。我几乎对每个 viewModel 都有类似 MyViewModelInitMessage
类 的东西,并且只需同时使用两种发布方法。
EventAggregator.Publish(new ChangePageMessage(typeof(MyViewModel)));
EventAggregator.Publish(new MyViewModelInitMessage("...all needed parameters"));
所以当我发布这两个时 - 我的 ViewModel
将被激活,然后它订阅 EventAggregator
(不要忘记这样做,否则第二个消息处理永远不会发生),然后将立即处理它的 InitMessage
。
现在使用 EventAggregator,您可以在当前订阅它的所有 ViewModel 之间发送消息。
这似乎是很常见的解决方案。