I've got a WPF application which calls MessageBox.Show() way back in the ViewModel (to check if the user really wants to delete). This actually works, but goes against the grain of MVVM since the ViewModel should not explicitly determine what happens on the View.
So now I am thinking how can I best implement the MessageBox.Show() functionality in my MVVM application, options:
I could have a message with the text "Are you sure...?" along with two buttons Yes and No all in a Border in my XAML, and create a trigger on the template so that it is collapsed/visible based on a ViewModelProperty called AreYourSureDialogueBoxIsVisible, and then when I need this dialogue box, assign AreYourSureDialogueBoxIsVisible to "true", and also handle the two buttons via DelegateCommand back in my ViewModel.
I could also somehow try to handle this with triggers in XAML so that the Delete button actually just makes some Border element appear with the message and buttons in it, and the Yes button did the actually deleting.
Both solutions seem to be too complex for what used to be a couple lines of code with MessageBox.Show().
In what ways have you successfully implemented Dialogue Boxes in your MVVM applications?
Services to the rescue. Using Onyx (disclaimer, I'm the author) this is as easy as:
public void Foo()
{
IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
dm.Show("Hello, world!");
}
In a running application, this will indirectly call MessageBox.Show("Hello, world!"). When testing, the IDisplayMessage service can be mocked and provided to the ViewModel to do what ever you want to accomplish during the test.
Of the two you mention, I prefer option #2. The Delete button on the page just makes the "Confirm Delete Dialog" appear. The "Confirm Delete Dialog" actually kicks off the Delete.
Have you checked out Karl Shifflett's WPF Line Of Business Slides and Demos? I know he does something like this. I'll try to remember where.
EDIT: Check out Demo #11 "Data Validation in MVVM" (EditContactItemsControlSelectionViewModel.DeleteCommand). Karl calls a popup from the ViewModal (What!? :-). I actually like your idea better. Seems easier to Unit Test.
To expand on Dean Chalk's answer now that his link is kaput:
In the App.xaml.cs file we hook up the confirm dialog to the viewmodel.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var confirm = (Func<string, string, bool>)((msg, capt) => MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes);
var window = new MainWindowView();
var viewModel = new MainWindowViewModel(confirm);
window.DataContext = viewModel;
...
}
In the view (MainWindowView.xaml) we have a button that calls a command in the ViewModel
<Button Command="{Binding Path=DeleteCommand}" />
The viewmodel (MainWindowViewModel.cs) uses a delegate command to show the "Are you sure?" dialog and perform the action. In this example it is a SimpleCommand
similar to this, but any implementation of ICommand should do.
private readonly Func<string, string, bool> _confirm;
//constructor
public MainWindowViewModel(Func<string, string, bool> confirm)
{
_confirm = confirm;
...
}
#region Delete Command
private SimpleCommand _deleteCommand;
public ICommand DeleteCommand
{
get { return _deleteCommand ?? (_deleteCommand = new SimpleCommand(ExecuteDeleteCommand, CanExecuteDeleteCommand)); }
}
public bool CanExecuteDeleteCommand()
{
//put your logic here whether to allow deletes
return true;
}
public void ExecuteDeleteCommand()
{
bool doDelete =_confirm("Are you sure?", "Confirm Delete");
if (doDelete)
{
//delete from database
...
}
}
#endregion
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With