Reputation: 10644
I have a button attached to a command in the view model. This button deletes the rows current selected in the listview so I would like to show a messagebox of confirmation before proceeding. Is user click ok button (in messagebox) then command is executed, otherwise, if user click cancel button command attached is not called. Is it possible? If so how?
<Button Name="btnDelete" Command="{Binding DeleteRowsCommand}"/>
Another possibility is to call the command on click and in the view model through a property that is attached to a custom message box placed in the view, to make this custom messagebox visible when value of the property is true. But then how can I send back to the view model which button 'Ok' or 'Cancel' has been pressed?
Upvotes: 3
Views: 3872
Reputation: 162
The view model doesn't often need to know that there is a question for the user before the command is executed. If that's the case, you can create very simple custom button class to just show the message box and if the user click yes, execute the command (or do whatever).
public class YesNoButton : Button
{
public string Question { get; set; }
protected override void OnClick()
{
if (string.IsNullOrWhiteSpace(Question))
{
base.OnClick();
return;
}
var messageBoxResult = MessageBox.Show(Question, "Confirmation", MessageBoxButton.YesNo);
if (messageBoxResult == MessageBoxResult.Yes)
base.OnClick();
}
}
In XAML you can use the button like this:
<components:YesNoButton Content="Delete rows" Command="{Binding DeleteRowsCommand}" Question="Do you really want to delete rows?" />
EDIT: Another way to solve this is to define some MessageBoxService in the ViewModel layer and implement it in View layer. Interface could look like this:
public interface IMessageBoxService
{
void ShowError(string messageBoxText);
void ShowWarning(string messageBoxText);
void ShowInformation(string messageBoxText);
}
This way you can show message boxes directly from the VM without directly referencing WPF libraries.
Upvotes: 6
Reputation: 1461
One of the possible (and in my opinion the cleanest) ways of doing this is to implement a service like DialogService, inject it into your ViewModel and call it when command is executed. By doing so you decouple your view and application logic so the ViewModel is completely unaware of how actually dialogs are shown and delegates all the work to the service. Here's an example.
First you create a dialog service which handles all the work of showing dialogs and returning their outcome:
public interface IDialogService
{
bool ConfirmDialog(string message);
}
public bool ConfirmDialog(string message)
{
MessageBoxResult result = MessageBox.Show(message, "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question);
return result == MessageBoxResult.Yes ? true : false;
}
Then you make your ViewModel dependent on that service and inject it in the ViewModel:
public class MyViewModel : ViewModelBase
{
private readonly IDialogService _dialogService;
public MyViewModel(IDialogService dialogService)
{
_dialogService = dialogService;
}
}
Finally in your command you call the service in your command to check whether the user is absolutely sure he wants to delete records or not:
public Command DeleteRecordsCommand
{
get
{
if (_deleteRecordsCommand == null)
{
_deleteRecordsCommand = new Command(
() =>
{
if (_dialogService.ConfirmDialog("Delete records?"))
{
// delete records
}
}
);
}
return _deleteRecordsCommand;
}
}
Upvotes: 0
Reputation: 6155
Just use a MessageBox
;)
In the method which is routed to the DeleteRowsCommand
use this
var result = MessageBox.Show("message", "caption", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
//your logic
}
Have a look at MessageBox Class for more information.
Upvotes: 2