views:

13

answers:

1

(Background: I'm porting a WinForms app to WPF in stages. At the present time, I still have a WinForms main form with an ElementHost that has WPF content in it.)

I'd like my app to be told when certain ApplicationCommands such as Cut, Copy, and Paste change the value of their .CanExecute. I thought it'd be a simple matter of subscribing to a global event like ApplicationCommands.Cut.CanExecuteChanged, but I am noticing some strange behavior where it doesn't seem to be called consistently.

For example, I created a simplified WinForms test app that just has an ElementHost. I then added a WPF textbox to it and attached CanExecuteChanged handlers to it:

public Form1()
{
   InitializeComponent();

   var tb = new System.Windows.Controls.TextBox {Text = "WPF Inside ElementHost"};

    ApplicationCommands.Cut.CanExecuteChanged += Cut_CanExecuteChanged;
    ApplicationCommands.Cut.CanExecuteChanged +=
        (s, e) => Debug.WriteLine("CanExecute Changed=" + ApplicationCommands.Cut.CanExecute(null, s as IInputElement));

    elementHost1.Child = tb;
}

private void Cut_CanExecuteChanged(object sender, System.EventArgs e)
{
    Debug.WriteLine("CanExecute Method for Cut = " + ApplicationCommands.Cut.CanExecute(null, sender as IInputElement));
}

The bizarre thing is that the handler that uses the inline lambda/delegate is called when I do things like select text in the textbox. However, the one that subscribes using an instance method does not get called.

Additionally, in my more complicated application, I'm not seeing the CanExecute get called at all, even when I use an inline delegate for the handler.

A: 

(In a case of using StackOverflow as a rubber duck, I realized the answer when I finished writing the question)

While reflector'ing around a bit, I saw that the CanExecuteChanged event simply passes the handler to CommandManager.RequerySuggested. Because this later event is a static event, it uses WeakReference handlers and prunes the list when it goes to raise the event. Since I wasn't keeping a hard reference around in the class, the GC was detecting that the reference was no longer valid and was getting pruned.

The solution was simply to add a class member variable that had the EventHandler and then use that member variable reference when attaching the event.

Jeff Moser