3

以下の例では Prism 6.1 の DelegateCommand を使用していますが、5.0 でも同じ問題が発生しました。

次のビューモデルを使用します (ビューは省略され、2 つのボタンのみで構成されます):

public class MainWindowViewModel
{
    public DelegateCommand TestCommand { get; set; }
    public DelegateCommand ActionCommand { get; set; }

    public MainWindowViewModel()
    {
        TestCommand = new DelegateCommand(()=> TestCommand.RaiseCanExecuteChanged());

        ActionCommand = new DelegateCommand(() =>
        {
            Task.Run(() =>
            {
                Thread.Sleep(1000);
                TestCommand.RaiseCanExecuteChanged();
            });
        });
    } 
}

ActiveCommand が最初に呼び出されると、次の例外が発生します。

タイプ 'System.InvalidOperationException' の例外が WindowsBase.dll で発生しましたが、ユーザー コードで処理されませんでした

追加情報: 別のスレッドがこのオブジェクトを所有しているため、呼び出しスレッドはこのオブジェクトにアクセスできません。

これは、私が知る限り、「UI スレッドを使用していない場合、Wpf コントロールと対話することは許可されていません」という標準的な例外です。これは、メソッドの要約と矛盾しているようです。

UI スレッドで Prism.Commands.DelegateCommandBase.CanExecuteChanged を発生させ、すべてのコマンド呼び出し元がコマンドを実行できるかどうかを確認するために再クエリできるようにします。

また、過去に非 UI スレッドからこのメソッドを呼び出すことに問題はありませんでした。

さらに奇妙なことに、最初に TestCommand が発生すると、ActionCommand が正常に動作し始めます。確認したところ、Task.Run ブロック内のコードはすべての場合において非 UI スレッドで実行されています。

残念ながら、実際のコードでこれを回避策として使用することはできません。ワーカー スレッドが呼び出す前に UI スレッドで RaiseCanExecuteChanged を呼び出そうとしましたが、役に立ちません。

RaiseCanExecuteChanged がこのように動作する理由はありますか? 修正または回避策はありますか?

4

1 に答える 1

1

UI スレッドで TestCommand を作成し、別のスレッドでアクセスしようとしています。そんなことはできません。実行したいのが can を上げるだけの場合は、Task.Run を待ってから呼び出します。

    public MainWindowViewModel()
    {
        TestCommand = new DelegateCommand(Test, CanTest);

        ActionCommand = new DelegateCommand(async () => 
        {
            await Task.Run(() =>
            {
                Thread.Sleep(1000);
            });

            TestCommand.RaiseCanExecuteChanged();
        });
    }
于 2015-11-11T22:30:05.493 に答える