26

I'm creating a standard menu in my WPF application.

I know that I can create custom commands, but I know there are also a bunch of standard commands to bind to.

For example, to open a file I should bind to ApplicationCommands.Open, to close a file I should bind to ApplicationCommands.Close. There's also a large number of EditCommands, ComponentCommands or NavigationCommands.

There doesn't seem to be an "Exit" command. I would have expected there to be ApplicationCommands.Exit.

What should I bind to the "Exit" menu item? To create a custom command for something this generic just seems wrong.

7 Answers 7

11

Unfortunately, there is no predefined ApplicationCommands.Exit. Adding one to WPF was suggested on Microsoft Connect in 2008: http://connect.microsoft.com/VisualStudio/feedback/details/354300/add-predefined-wpf-command-applicationcommands-exit. The item has been marked closed/postponed, however.

Mike Taulty discussed how to create your own Exit command in an article on his blog.

Sign up to request clarification or add additional context in comments.

Comments

7

AFAIK there's no ApplicationCommands.Quit or ApplicationCommands.Exit, so I guess you're gonna have to create it yourself...

Anyway, if you're using the MVVM pattern, RoutedCommands are not exactly handy, so it's better to use a lightweight alternative like RelayCommand or DelegateCommand.

Comments

6

Not that complex actually (but still, M$ sucks for not providing it). Here you go:

public static class MyCommands
{
    private static readonly ICommand appCloseCmd = new ApplicationCloseCommand();
    public static ICommand ApplicationCloseCommand
    {
        get { return appCloseCmd; }
    }
}

//===================================================================================================
public class ApplicationCloseCommand : ICommand
{
    public event EventHandler CanExecuteChanged
    {
        // You may not need a body here at all...
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return Application.Current != null && Application.Current.MainWindow != null;
    }

    public void Execute(object parameter)
    {
        Application.Current.MainWindow.Close();
    }
}

And the body of the AplicationCloseCommand.CanExecuteChanged event handler may not be even needed.

You use it like so:

<MenuItem Header="{DynamicResource MenuFileExit}" Command="MyNamespace:MyCommands.ApplicationCloseCommand"/>

Cheers!

(You cannot imagine how long it took me to discover this Command stuff myself...)

Comments

4

Yes, it would've made a lot of sense for Microsoft to include an ApplicationCommands.Exit command in their collection of pre-defined commands. It disappoints me that they didn't. But as the answers to this question demonstrate, not all is lost.

There are lots of workarounds possible for the lack of a proper ApplicationCommands.Exit object. However, I feel most miss the point. Either they implement something in the view model, for something that really is strictly a view behavior (in some cases reaching into the view object graph with e.g. Application.Current.MainWindow!), or they write a bunch of code-behind to do what XAML does very well and much more conveniently.

IMHO, the simplest approach is just to declare a RoutedUICommand resource for the window, attach that to a command binding, and to a menu item, to hook all the parts up. For example:

<Window x:Class="ConwaysGameOfLife.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

  <Window.Resources>
    <RoutedUICommand x:Key="fileExitCommand" Text="File E_xit">
      <RoutedUICommand.InputGestures>
        <KeyGesture >Alt+F4</KeyGesture>
      </RoutedUICommand.InputGestures>
    </RoutedUICommand>
  </Window.Resources>

  <Window.CommandBindings>
    <CommandBinding Command="{StaticResource fileExitCommand}" Executed="fileExitCommand_Executed"/>
  </Window.CommandBindings>

  <DockPanel>
    <Menu DockPanel.Dock="Top">
      <MenuItem Header="_File">
        <!-- other menu items go here -->
        <Separator/>
        <MenuItem Command="{StaticResource fileExitCommand}"/>
      </MenuItem>
    </Menu>
    <!-- the main client area UI goes here -->
  </DockPanel>

</Window>

The Executed event handler for the command binding is trivial:

private void fileExitCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
    Close();
}

Assuming, of course, your program implementation follows the usual semantics of closing the main window to exit the program.

In this way, all of the UI-specific elements go right into the RoutedUICommand object, which can be configured correctly and conveniently right in the XAML rather than having to declare a new C# class to implement the command and/or mess around with the input bindings from code-behind. The MenuItem object already knows what to do with a RoutedUICommand in terms of display, so going this route provides a nice decoupling of the command's properties from the rest of the UI. It also provides a convenient way to provide a secondary key gesture, in case you'd prefer something other than the default Alt+F4 (e.g. Ctrl+W).

You can even put the RoutedUICommand declaration in the App.xaml file, for reuse among multiple windows in your program, should they exist. Again, decoupling the UI-specific aspects, which are declared in the resource, from the consumers that are found throughout the program.

I find this approach much more generalizable and easily implemented than the other options which I've seen presented (here and elsewhere).

Comments

1
private void MenuItem_Click(object sender, RoutedEventArgs e)
    {
        Application.Current.Shutdown();
    }

Comments

1

Pretty simple to do:

using System.Windows.Input;

namespace YourApp
{
    static class ApplicationCommands
    {    
        public static RoutedCommand Quit { get; }    

        static ApplicationCommands()
        {
            var inputGestures = new InputGestureCollection();
            inputGestures.Add(new KeyGesture(Key.Q, ModifierKeys.Control));
            Quit = new RoutedUICommand("Quit", "Quit", typeof(ApplicationCommands),
                inputGestures);
        }
    }
}

Use it in your XAML like this:

<Window.CommandBindings>
    <CommandBinding Command="local:ApplicationCommands.Quit" 
                    Executed="QuitCommandOnExecuted"/>
</Window.CommandBindings>

[..]

<MenuItem Command="local:ApplicationCommands.Quit" />

Code-behind:

void QuitCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
{
    Application.Current.Shutdown();
}

Comments

-1

You can modify the Text property of a command before you bind it in a window. This will change the text of the command everywhere it appears in your ui.

EDIT: Do this to Close in the Window or App ctor

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.