1

(背景:WinFormsアプリを段階的にWPFに移植しています。現時点では、WPFコンテンツを含むElementHostを含むWinFormsメインフォームがまだあります。)

CutCopyPasteなどの特定のApplicationCommandが.CanExecuteの値を変更したときに、アプリに通知を受け取りたいのですが。ApplicationCommands.Cut.CanExecuteChangedのようなグローバルイベントをサブスクライブするのは簡単なことだと思いましたが、一貫して呼び出されていないように見える奇妙な動作に気づいています。

たとえば、ElementHostだけを含む単純化されたWinFormsテストアプリを作成しました。次に、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));
}

奇妙なことに、テキストボックスでテキストを選択するなどの操作を行うと、インラインラムダ/デリゲートを使用するハンドラーが呼び出されます。ただし、インスタンスメソッドを使用してサブスクライブするものは呼び出されません。

さらに、より複雑なアプリケーションでは、ハンドラーにインラインデリゲートを使用している場合でも、CanExecuteがまったく呼び出されません。

4

1 に答える 1

3

(StackOverflowをラバーダックとして使用する場合、質問を書き終えたときに答えに気づきました)

リフレクターを少し回していると、CanExecuteChangedイベントがハンドラーをCommandManager.RequerySuggestedに渡すだけであることがわかりました。この後のイベントは静的イベントであるため、WeakReferenceハンドラーを使用して、イベントを発生させるときにリストを削除します。クラス内でハードリファレンスを保持していなかったため、GCは、リファレンスが無効になり、整理されていることを検出していました。

解決策は、EventHandlerを持つクラスメンバー変数を追加し、イベントをアタッチするときにそのメンバー変数参照を使用することでした。

于 2010-07-12T18:15:14.973 に答える