How can I cancel exiting from particular form after Cancel button (or X at the top right corner, or Esc) was clicked?
WPF:
<Window
...
x:Class="MyApp.MyView"
...
/>
<Button Content="Cancel" Command="{Binding CancelCommand}" IsCancel="True"/>
</Window>
ViewModel:
public class MyViewModel : Screen {
private CancelCommand cancelCommand;
public CancelCommand CancelCommand {
get { return cancelCommand; }
}
public MyViewModel() {
cancelCommand = new CancelCommand(this);
}
}
public class CancelCommand : ICommand {
public CancelCommand(MyViewModel viewModel) {
this.viewModel = viewModel;
}
public override void Execute(object parameter) {
if (true) { // here is a real condition
MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show(
"Really close?", "Warning",
System.Windows.MessageBoxButton.YesNo);
if (messageBoxResult == MessageBoxResult.No) { return; }
}
viewModel.TryClose(false);
}
public override bool CanExecute(object parameter) {
return true;
}
}
Current code doesn't work. I want user to stay on current form if it chooses 'No' in popup dialog. Also, overriding CanExecute doesn't help. It just disables the button. I want to allow user to hit the button, but then notify him/her, that data will be lost. Maybe I should assign an event listener on button?
EDIT:
I managed showing popup on Cancel button. But I still can't manage Esc or X button (top right). It seems I was confused with Cancel button, because Execute method is executed when I click X button or Esc.
EDIT2:
I changed the question. It was 'how cancel Cancel button'. However, it wasn't what I was looking for. I need to cancel Esc or X button. In 'MyViewModel' I add:
protected override void OnViewAttached(object view, object context) {
base.OnViewAttached(view, context);
(view as MyView).Closing += MyViewModel_Closing;
}
void MyViewModel_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (true) {
MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show(
"Really close?", "Warning",
System.Windows.MessageBoxButton.YesNo);
if (messageBoxResult == MessageBoxResult.No) {
e.Cancel = true;
}
}
}
This solved my problem. However, I need ICommand to understand, which button was clicked, Save or Cancel. Is there any way to eliminate usage of event?
I'm not an MVVM expert, but in my opinion Yusufs' answer isn't quite MVVM. On the other hand Torpederos answer is a bit complicated for only close cancellation. Here is my approach. In this example I subscribed to the closing event, but it is always cancelled
private void OnClosing(object sender, CancelEventArgs e)
{
e.Cancel = true;
return;
}
In the XAML I added this
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding Close}" />
</i:EventTrigger>
</i:Interaction.Triggers>
And finally in the view model
public ICommand Close { get; set; }
Close = new RelayCommand(CommandClose);
private void CommandClose(object sender)
{
if (Dirty)
{
// Save your data here
}
Environment.Exit(0);
}
In this approach the the closing event is triggered first. That cancels the closing. After that the interaction trigger is invoked and triggers the code in the view model via the RelayCommand. In the view model I can use the Dirty flag that is not accessible in the view.
You are trying to do View's work in ViewModel class. Let your View class to handle the closing request and whether it should be canceled or not.
To cancel closing of a window you can subscribe to the Closing
event of view and set CancelEventArgs.Cancel
to true after showing a MessageBox
.
Here is an example:
<Window
...
x:Class="MyApp.MyView"
Closing="OnClosing"
...
/>
</Window>
Code behind:
private void OnClosing(object sender, CancelEventArgs e)
{
var result = MessageBox.Show("Really close?", "Warning", MessageBoxButton.YesNo);
if (result != MessageBoxResult.Yes)
{
e.Cancel = true;
}
// OR, if triggering dialog via view-model:
bool shouldClose = ((MyViewModel) DataContext).TryClose();
if(!shouldClose)
{
e.Cancel = true;
}
}
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