(背景:我正在分阶段将WinForms应用程序移植到WPF。目前,我仍然有一个WinForms主窗体,其中包含一个包含WPF内容的ElementHost。)
我希望在某个ApplicationCommands,例如Cut,Copy和Paste更改其.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被调用,即使我使用内联委托处理程序。
答案 0 :(得分:3)
(在使用StackOverflow作为rubber duck的情况下,我在写完问题时意识到了答案)
虽然有点反射,但我看到CanExecuteChanged事件只是将处理程序传递给CommandManager.RequerySuggested。因为这个后来的事件是静态事件,所以它使用WeakReference处理程序并在提升事件时修剪列表。由于我没有在课堂上保留一个硬参考,因此GC检测到该参考不再有效并且正在修剪。
解决方案只是添加一个具有EventHandler的类成员变量,然后在附加事件时使用该成员变量引用。