I've created my first MVVMLight project, and I've a question:
I've a button, on which is bound a command. When the command execute, in different use cases, I've to get/give information to the enduser, like:
I know that I can do a MessageBox.Show
/... but where? Because in regards of the separation of concerns I guess it should be in the ViewModel? So what is the mecanism in place that I should use for this?
My ViewModel is basically like this:
public class MainViewModel : BaseViewModel
{
private static readonly Logger m_logger = LoggerProvider.GetLogger("MyPath.MainViewModel");
private ISerializationService m_serializationService;
public ICommand TrySaveCommand { get; set; }
//Lot of other fields here
public MainViewModel()
{
m_serializationService = ServiceLocator.Current.GetInstance<ISerializationService>();
TrySaveCommand = new RelayCommand(TrySave);
}
private void TrySave()
{
DispatcherHelper.RunAsync(() =>
{
//Here I need to get the path where I save on some condition
m_serializationService.SaveProject(pathIGotFromTheUser);
//Give a feedback that everything has been correctly saved(for test purpose, a MessageBox.Show() )
});
}
}
So how should I do to get information from the user on the file to save? (with SaveFileDialog
) and display that it has correctly been saved (with MessageBox.Show
)
Thank you
Laurent Bugnion in his mvvmlight library introduced a very handy helper class called Messenger
, using it you can send and receive notifications and/or information between the viewmodels, views or viewmodel/view.
here how it works
Messenger.Default.Send<..>(..)
the viewmodel broadcast a message,Messenger.Default.Register<>(..)
) and based on that notification an appropriate logic is executed (showing message or a Dialog box for example ..)to apply this in your case you must add some view related logic to your code behind, to show DialogueBox and confirmation messages. MainWndow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
Messenger.Default.Register<NotificationMessage>(this, (m) =>
{
switch (m.Notification)
{
case "SaveFile":
var dlg = new SaveFileDialog();
if (dlg.ShowDialog() == true)
{
var filename = dlg.FileName;
Messenger.Default.Send<String>( filename,"FileSaved");
}
break;
case "WentWell":
MessageBox.Show("Everything went well Wohoo");
break;
}
});
}
}
here the view will show a dialog box or a confirmation message box based on the broadcast-ed ViewModel notification
and in the MainWindowViewModel
public class MainViewModel : ViewModelBase
{
private static readonly Logger m_logger = LoggerProvider.GetLogger("MyPath.MainViewModel");
private ISerializationService m_serializationService;
private RelayCommand _trySaveCommand;
public RelayCommand TrySaveCommand
{
get
{
return _trySaveCommand
?? (_trySaveCommand = new RelayCommand(
() =>
{
Messenger.Default.Send(new NotificationMessage("SaveFile"));
}));
}
}
public MainViewModel()
{
m_serializationService = ServiceLocator.Current.GetInstance<ISerializationService>();
Messenger.Default.Register<string>(this, "FileSaved", (pathIGotFromTheUser) =>
{
m_serializationService.SaveProject(pathIGotFromTheUser);
//Give a feedback that everything has been correctly saved(for test purpose, a MessageBox.Show() )
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("WentWell"));
});
}
the TrySaveCommand associated to a button or whatever will trigger the view.
**and before you said it, i don't believe that you are violating any mvvm rule by doing that, showing message boxes or dialogues is a presentation related logic and should be handled in the Views part of your solution; the view model by sending a message don't actually know any think about the view, he simply do some work and broadcast a status message, and finally here some in depth information about the Messenger Class HERE.