Thursday, July 2, 2015

e.OriginalSource in RoutedCommands is unreliable

I came across an interesting WPF bug (Framework 4.0) today that warrants documenting.

I wanted to have a RoutedCommand.Executed event handler reach through to the MenuItem that triggered the command and read the Tag property for some extra information because the CommandParameter was already occupied with something else. The idea was the the following XAML


<CommandBinding Command="Open" CanExecute="OpenCanExecute" Executed="OpenExecuted" />
.
.
.
<MenuItem Header="Edit" Command="Open" CommandParameter="Vendor.Maintenance" Tag="Edit"/>

would execute code that could use e.OriginalSource to get the value of Tag but from time to time the OriginalSource would be the textbox that had focus instead of the MenuItem that actually initiated the RoutedCommand. Clearly this is a bug in WPF

In the end I solved the problem by making the syntax of CommandParameter more flexible.

In the example above you can see the CommandParameter is in the format <string>.<string>. But a CommandParameter is an object so you can populate it with anything you want. I discovered a way to populate a CommandParameter with an array of strings declaratively in XAML.

Start by making sure you have the following two XMLNS declarations in your main tag.

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"

and now try the following XAML

<Menu IsMainMenu="true">
    <MenuItem Header="Edit" Command="Open">
        <MenuItem.CommandParameter>
            <x:ArrayExtension Type="sys:String">
                <sys:String>Vendor</sys:String>
                <sys:String>Maintenance</sys:String>
                <sys:String>Edit</sys:String>
            </x:ArrayExtension>
        </MenuItem.CommandParameter>
    </MenuItem>
</Menu>

No comments:

Post a Comment