Disabled ContextMenus in WPF bug

by Trent Guidry 14. June 2009 06:49

WPF ContextMenus with RoutedCommands and CommandBindings can be disabled due to a focusing issue that appears to be a bug in WPF.

A while back I was working with WPF ContextMenus that used RoutedCommands and CommandBindings and ran into issues with getting the MenuItems in the ContextMenu to enable.  I managed to reproduce this issue with some fairly simple code and will elaborate on the issue and its workaround in this post.

To see this issue, consider the code below:

XAML

<Window x:Class="WpfApplication3.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Window1" Height="403" Width="621" Loaded="Window_Loaded">

    <Window.CommandBindings>

        <CommandBinding Command="Open" CanExecute="cbOpen_CanExecute" Executed="cbOpen_Executed"/>

        <CommandBinding Command="Print" CanExecute="cbPrint_CanExecute" Executed="cbPrint_Executed"/>

    </Window.CommandBindings>

    <Window.ContextMenu>

        <ContextMenu>

            <MenuItem Header="Open" Command="Open"/>

            <MenuItem Header="Print" Command="Print"/>

        </ContextMenu>

    </Window.ContextMenu>

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

        <Menu Grid.Row="0">

            <MenuItem Header="File">

                <MenuItem Header="Open" Command="Open"/>

                <MenuItem Header="Print" Command="Print"/>

            </MenuItem>

        </Menu>

        <Button Content="Button" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="106,114,0,0" Name="button1" VerticalAlignment="Top" Width="75">

            <Button.ContextMenu>

                <ContextMenu>

                    <MenuItem Header="Open" Command="Open"/>

                    <MenuItem Header="Print" Command="Print"/>

                </ContextMenu>

            </Button.ContextMenu>

        </Button>

    </Grid>

</Window>

 

C#

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

 

namespace WpfApplication3

{

    /// <summary>

    /// Interaction logic for Window1.xaml

    /// </summary>

    public partial class Window1 : Window

    {

        public Window1()

        {

            InitializeComponent();

        }

 

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

        }

 

        private void cbOpen_CanExecute(object sender, CanExecuteRoutedEventArgs e)

        {

            e.CanExecute = true;

        }

 

        private void cbOpen_Executed(object sender, ExecutedRoutedEventArgs e)

        {

            MessageBox.Show("Open");

        }

 

        private void cbPrint_CanExecute(object sender, CanExecuteRoutedEventArgs e)

        {

            e.CanExecute = true;

        }

 

        private void cbPrint_Executed(object sender, ExecutedRoutedEventArgs e)

        {

            MessageBox.Show("Print");

        }

 

    }

}

 

Basically, this code consists of a window with two command bindings, one to Open and one to Print.  The Executed event of both are wired up to show a message box with the command name and the CanExecute events are wired to set the CanExecute property of the event argument to true.

This window has a menu which is wired up to the two commands, a context menu wired up to the two commands, and a button with a context menu wired up to the two commands.

When this application is run, the top level menu works as expected, however, for both of the context menus, the menu items are disabled.  After clicking the button however, both the context menu on the window and the context menu on the button work correctly.

That sort of behavior is obviously not what I wanted.  The context menus should work without first having to click the button.  To try and get it to work, after InitializeComponent() in the window constructor, I added, button1.Focus() and, strangely, that fixed the context menu issue.

Since having to call focus on an element in the window is a total kludge, I Googled around to see if anyone else had run into this issue and if they had a better fix than the one I was using.  After spending an hour or so digging through posts on Google, I finally found  WPF RoutedCommands not routing correctly in a ContextMenu, which actually gives a pretty good explanation as to why this happens and also points out that calling Focus() also works.

Basically, it appears that this issue is due to a bug in WPF.  There is an active bug report on Microsoft Connect about it and the easiest way to work around it that I have found so far is to call Focus(); right after InitializeComponent(); in the window constructor.

Tags: ,

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading