2013-02-22 3 views
8

コマンドを使用してViewModelに結び付けられたボタン付きの単純なウィンドウがあります。コマンドCanExecuteがfalseのときにボタンが無効にならない

MyCommand.CanExecute()がfalseの場合、ボタンが無効になると予想します。しかし、WPFはウィンドウが最初に描画されたときにのみIsEnabledプロパティを設定するようです。それ以降のアクションは、ボタンの可視状態には影響しません。私はPrismからDelegateCommandを使用しています。

マイビュー:

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <Button Content="Click Here" Command="{Binding MyCommand}" Width="100" Height="50"/> 
</Grid> 

と私のViewModel:時間の

public class MyVM : NotificationObject 
{ 
    public MyVM() 
    { 
     _myCommand = new DelegateCommand(DoStuff, CanDoStuff); 
    } 

    private void DoStuff() 
    { 
     Console.WriteLine("Command Executed"); 
     _myCommand.RaiseCanExecuteChanged(); 
    } 

    private bool CanDoStuff() 
    { 
     var result = DateTime.Now.Second % 2 == 0; 
     Console.WriteLine("CanExecute is {0}", result); 
     return result; 
    } 

    private DelegateCommand _myCommand; 

    public ICommand MyCommand 
    { 
     get 
     { 
      return _myCommand; 
     } 
    } 
} 

50%、私のアプリケーションの負荷が、ボタンが適切に無効になっています。しかし、ウィンドウがロードされたときに有効になっていて、コマンドを実行するためにボタンをクリックすると、ボタンが無効になる時間は50%になると思いますが、それは決してありません。コマンドは実行されませんが、ボタンをクリックすることはできます。 CanExecute()がfalseのときにボタンを無効にする必要があることをWPFに理解させるにはどうすればよいですか?

+0

まず最初は、データバインディングのデバッグメッセージを上げている(Microsoft.Practices.Prism.dllが必要である)、これを試すことができます:http://i.stack.imgur.com/MF8i5.png次に、再実行して出力ウィンドウを確認し、そこにどのようなエラーがあるかを確認してください。あなたのコマンドバインディングに関係しないものがあれば、 'RaiseCanExecuteChanged()'の実装は不正確/バグです。 – Will

+0

あなたのCanDOStuffメソッドは本当に奇妙です!それはあなたのボタンを無効にすることができますが、次の秒であなたのコマンドを実行することができますが、ボタンは無効になっています...本当に厄介です。 CanExecuteが変更され、UIが変更されない場合は、[CommandManager.InvalidateRequerySuggested()](http://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerysuggested.aspx)を呼び出す必要がありますCanExecuteChangedが呼び出されなかったために更新されました。 –

+0

@Viktor私はそれが本当に奇妙であることを知っています、それはtrue/falseをランダムに返すばかげた例であると考えられています。 CommandManager.InvalidateRequerySuggestedは効果がありません。 –

答えて

6

私はあなたがプリズムとそのNotificationObjectDelegateCommandを使用しているのを見ていますので、RaiseCanExecuteChanged()にバグがないはずです。

しかし、その理由は、プリズムのRaiseCanExecuteChangedが同期して動作するため、ICommand.Execute()の実装内にある間にCanDoStuff()が呼び出され、その結果が無視されるように見えるからです。

独自のコマンドで別のボタンを作成し、そのコマンド/ボタンから_myCommand.RaiseCanExecuteChanged()を呼び出すと、最初のボタンが期待どおりに有効/無効になります。

それとも、あなたはMVVM光で同じことを試してみて、RelayCommand場合非同期 Dispatcher.CurrentDispatcher.BeginInvokeを使用して CanDoStuffにコールバックを呼び出しMVVMライトの RaiseCanExecuteChanged呼び出しが CommandManager.InvalidateRequerySuggested()、あなたがプリズムの実装を見ている行動を避けるために、あなたのコードが動作します。

+0

ありがとうございます。私はあなたの提案を試してみました。 Prismの不幸な制限のようだ。 –

0

あなたはあなたがする必要がある

public class ViewModel 
{ 
    public DelegateCommand ExportCommand { get; } 

    public ViewModel() 
    { 
     ExportCommand = new DelegateCommand(Export, CanDoExptor); 
    } 

    private void Export() 
    { 
     //logic 
    } 

    private bool _isCanDoExportChecked; 

    public bool IsCanDoExportChecked 
    { 
     get { return _isCanDoExportChecked; } 
     set 
     { 
      if (_isCanDoExportChecked == value) return; 

      _isCanDoExportChecked = value; 
      ExportCommand.RaiseCanExecuteChanged(); 
     } 
    } 

    private bool CanDoExptor() 
    { 
     return IsCanDoExportChecked; 
    } 
} 
関連する問題