在wpf应用程序的mvvm中实现导航的最佳方式
本文关键字:导航 最佳 方式 实现 mvvm wpf 应用程序 | 更新日期: 2023-09-27 18:29:31
我在当前WPF应用程序分配中实现MVVM。
我创建了一个基类,它继承Window,然后每隔一个窗口都继承这个类。
public class ApplicationScreenBase : Window
{
public ApplicationScreenBase()
{
AppMessenger.Register(this, OnMessageToApp);
this.Unloaded += ApplicationScreenBase_Unloaded;
}
private void ApplicationScreenBase_Unloaded(object sender, RoutedEventArgs e)
{
AppMessenger.Unregister(this, OnMessageToApp);
}
private void OnMessageToApp(AppMessage message)
{
switch (message.MessageType)
{
case AppMessageType.Navigate:
{
var CurrentWindow = Activator.CreateInstance(Locator.NavigationPageLocator.LocateNavigateTypeByEnum((NavigationScreens)message.MessageData)) as Window;
CurrentWindow.Show();
this.Close();
break;
}
case AppMessageType.NewWindow:
{
var CurrentWindow = Activator.CreateInstance(Locator.NavigationPageLocator.LocateNavigateTypeByEnum((NavigationScreens)message.MessageData)) as Window;
CurrentWindow.Show();
break;
}
case AppMessageType.MessageBox:
{
MessageBox.Show(message.MessageData.ToString());
break;
}
case AppMessageType.Close:
{
this.Close();
break;
}
default:
break;
}
}
}
这是我的导航类,它返回我要打开的窗口类型。
public static class NavigationPageLocator
{
public static Type LocateNavigateTypeByEnum(NavigationScreens navigationPage)
{
switch (navigationPage)
{
case NavigationScreens.LoginOnline:
return typeof(LoginOnline);
case NavigationScreens.MainWindow:
return typeof(MainWindow);
case NavigationScreens.Home:
return typeof(Home);
}
return default(Type);
}
}
这就是我如何使用AppMessenger
public enum AppMessageType
{
Navigate,
NewWindow,
Close,
MessageBox
}
public class AppMessage
{
public AppMessageType MessageType { get; set; }
public object MessageData { get; set; }
}
public class AppMessenger
{
public static void Register(object recipient, Action<AppMessage> action)
{
Messenger.Default.Register<AppMessage>(recipient, action);
}
public static void Unregister(object recipient, Action<AppMessage> action)
{
Messenger.Default.Unregister<AppMessage>(recipient, action);
}
public static void Send(AppMessage message)
{
Messenger.Default.Send<AppMessage>(message);
}
这是我从ViewModel-控制流量的某种方式
AppMessenger.Send(new AppMessage() { MessageType = AppMessageType.Navigate, MessageData = NavigationScreens.Home });
现在的问题是,我成功地注册到了窗口,我发现每个窗口都有一个AppMessenger实例注册到,但当我通知messenger调用某个事件时,它会触发两次。例如
AppMessenger.Send(new AppMessage() { MessageType = AppMessageType.MessageBox, MessageData = "Authentication failed." });
这将显示两次MessageBox。
为什么它开了两次火。我该如何防止这种情况发生?
您可以考虑另一个类(WindowManger),它可以为您主控窗口。您正在创建一个新的导航窗口。在这里,如果窗口已经存在,您可以从WindowManager中进行检查。
从本质上讲,导航的问题在于,您希望将通常复杂的导航逻辑与每个内容"页面"关联的UI和业务逻辑解耦。这基本上是通过NavigationPageLocator
类和基于消息的通信系统来实现的。
您似乎正在沿着正确的路线来实现自己的解决方案,尽管您可能会发现自己必须做大量的"管道"工作才能实现一些更高级的场景。您可能需要查看有关WPF应用程序中导航的PRISM文档,它提供了一个现成的解决方案。
好的,我在这里找到了我的解决方案
public ApplicationScreenBase()
{
this.Loaded +=ApplicationScreenBase_Loaded;
this.Unloaded += ApplicationScreenBase_Unloaded;
this.Activated += ApplicationScreenBase_Activated;
this.Deactivated += ApplicationScreenBase_Deactivated;
}
void ApplicationScreenBase_Deactivated(object sender, EventArgs e)
{
AppMessenger.Unregister(this, OnMessageToApp);
}
void ApplicationScreenBase_Activated(object sender, EventArgs e)
{
AppMessenger.Register(this, OnMessageToApp);
}
实际情况是,如果我打开两个窗口,那么AppMessenger会发送两次消息,因为这两个窗口当前都已在AppMessenger中注册。因此,使用窗口生命周期,我将Appmessenger注销到后台窗口,并注册到后台窗口。这样,只有一个窗口会注册到Appmessenger,但我怀疑如果两个窗口都处于最小化状态的前台会发生什么。希望这对将来的人有所帮助。