I implement MVVM in my current WPF application assignment.
I created a base class which inherit Window and then every other window inherit this class.
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;
}
}
}
This is my navigation class which return me Type of window to open.
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);
}
}
This is how I use 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);
}
And this is some way I control the flow from ViewModel-
AppMessenger.Send(new AppMessage() { MessageType = AppMessageType.Navigate, MessageData = NavigationScreens.Home });
Now the problem is I register to window successfully and I found that a single instance of AppMessenger is register to per Window but when I notify messenger to invoke some event it fires twice. For e.g.
AppMessenger.Send(new AppMessage() { MessageType = AppMessageType.MessageBox, MessageData = "Authentication failed." });
This will show two time MessageBox.
Why did it fire twice. How can I prevent this?
Ok, here i found my solution
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);
}
What is happening is, if i open two windows then AppMessenger send message twice as both windows are currently registered with AppMessenger. So using Window life cycle i unregister Appmessenger to the window which is in background and register which is in forground this way, only one window will be registered to the AppMessenger, but i doubt what happen if both windows are in foreground in minimize state. Hope this may help someone in future.