Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confirmation when closing WPF window with 'X' button or ESC-key

Tags:

c#

wpf

How can I request confirmation when closing WPF window in desktop application with click 'X' button or by pressing ESC-key?
I would like to make it with a minimum of code.
Similar issue is here but on MVVM Light and there is too much code.

like image 592
ofodjs Avatar asked Oct 25 '13 12:10

ofodjs


People also ask

How do I close a WPF window?

Pressing ALT + F4 . Pressing the Close button.

How do I hide the close button in WPF window?

In the code-behind, create the class for the window. // // C# Code, CustomWindow class declaration // public partial class CustomWindow : Window { // Prep stuff needed to remove close button on window private const int GWL_STYLE = -16; private const int WS_SYSMENU = 0x80000; [System. Runtime. InteropServices.

How do I know if a WPF window is open?

Windows. OfType<T>(). Any()) // Check is Not Open, Open it.

How do you open a new window when a button is clicked in WPF?

To add a new Window to your project: Right Click on your Project --> Add --> New Element --> Window. Name it as you please, I will use the default (Window1). Now you can modify this window in the same way as you did for your original window.


1 Answers

I was looking for a more MVVM way of doing it. So here's what worked for me.

The Window code

<Window x:Class="My.Namespace.Wpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    mc:Ignorable="d" 
    Closing="Window_Closing">
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Closing">
        <i:InvokeCommandAction Command="{Binding ExitApplicationCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

The code behind

/// <summary>
/// Handles the Closing event of the Window control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    e.Cancel = !_viewModel.ShouldCloseApp;
}

The command in the view model

public bool ShouldCloseApp { get; private set; }

private RelayCommand<Window> _exitApplicationCommand;

public RelayCommand<Window> ExitApplicationCommand
{
    get
    {
        if (_exitApplicationCommand == null)
        {
            _exitApplicationCommand = new RelayCommand<Window>(exitApplicationCommand);
        }

        return _exitApplicationCommand;
    }
}

/// <summary>
/// This closes a specified window.  If you pass the main window, then this application 
/// will exit.  This is because the application shut down mode is set to OnMainWindowClose.
/// </summary>
/// <param name="window">The window to close.</param>
private void exitApplicationCommand(Window window)
{
    try
    {
        DialogService.ShowConfirmation(
            UIStrings.MainWindowViewModel_ExitProgramHeader,
            UIStrings.MainWindowViewModel_ExitProgramMessage,
            UIStrings.MainWindowViewModel_ExitProgramAcceptText,
            UIStrings.MainWindowViewModel_ExitProgramCancelText,
            (DialogResult result) =>
            {
                if ((result.Result.HasValue) && (result.Result.Value))
                {
                    if (ElectroTekManager.Manager.ConnectedElectroTek != null)
                    {
                        SendToStatusOperation operation = new SendToStatusOperation(ElectroTekManager.Manager.ConnectedElectroTek, (operationResult, errorMessage) =>
                        {
                            if (operationResult != FirmwareOperation.OperationResult.Success)
                            {
                                log.Debug(string.Format("{0} {1}", CautionStrings.MainWindowViewModel_LogMsg_UnableToSendToStatus, errorMessage));
                            }
                            else if (!string.IsNullOrEmpty(errorMessage))
                            {
                                log.Debug(errorMessage);
                            }

                            Application.Current.Dispatcher.Invoke(new Action(() => closeApp(window)));
                        });

                        operation.Execute();
                    }
                    else
                    {
                        closeApp(window);
                    }
                }
            });
    }
    catch (Exception ex)
    {
        log.Debug(CautionStrings.MainWindowViewModel_LogMsg_FailedToShowConfirmation, ex);
    }
}

/// <summary>
/// Closes the application.
/// </summary>
/// <param name="window">The window.</param>
private void closeApp(Window window)
{
    ShouldCloseApp = true;

    Dispose();

    Application.Current.Shutdown();
}

After the confirmation, I call Application.Current.Shutdown(). This triggers the closing event in the code behind a second time, but will not trigger the exit command again.

like image 156
Matt Becker Avatar answered Sep 20 '22 18:09

Matt Becker