RoutedCommand.CanExecuteChanged事件未在ElementHost中一致地触发

时间:2010-07-12 18:15:01

标签: wpf routed-commands

(背景:我正在分阶段将WinForms应用程序移植到WPF。目前,我仍然有一个WinForms主窗体,其中包含一个包含WPF内容的ElementHost。)

我希望在某个ApplicationCommands,例如CutCopyPaste更改其.CanExecute的值时,会告知我的应用。我认为订阅像ApplicationCommands.Cut.CanExecuteChanged这样的全局事件是一件简单的事情,但我注意到一些奇怪的行为,似乎并没有被一致地调用。

例如,我创建了一个简单的WinForms测试应用程序,它只有一个ElementHost。然后我向它添加了一个WPF文本框,并将CanExecuteChanged处理程序附加到它:

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));
}

奇怪的是,当我在文本框中选择文本时,会调用使用内联lambda / delegate的处理程序。但是,使用实例方法订阅的那个不会被调用。

此外,在我更复杂的应用程序中,我根本没有看到CanExecute被调用,即使我使用内联委托处理程序。

1 个答案:

答案 0 :(得分:3)

(在使用StackOverflow作为rubber duck的情况下,我在写完问题时意识到了答案)

虽然有点反射,但我看到CanExecuteChanged事件只是将处理程序传递给CommandManager.RequerySuggested。因为这个后来的事件是静态事件,所以它使用WeakReference处理程序并在提升事件时修剪列表。由于我没有在课堂上保留一个硬参考,因此GC检测到该参考不再有效并且正在修剪。

解决方案只是添加一个具有EventHandler的类成员变量,然后在附加事件时使用该成员变量引用。