2012-05-18 11 views
9

commandのプロパティが一部のコレクションの現在のアイテムのICommandにバインドされているボタンがあるとします。現在のアイテムがない場合、現在のアイテムのICommandにバインドされたボタンを無効にするにはどうすればよいですか?

コレクションがnullの場合、ボタンは有効のままで、クリックすると操作がないように見えます。代わりにボタンが無効のままであるようにしたい。私は、コレクションがnullのときは常にボタンを無効にしておくために次のことを考え出しました。しかし、少し複雑すぎて、(おそらく)がより自然でシンプルでMVVMのように遂行されていると思われます。

したがって、疑問点:そのボタンを無効にしておくと、コードビハインドを使用しないのが理想的です。

の.xaml:

<Button Content="Do something" > 
    <Button.Command> 
     <PriorityBinding> 
      <Binding Path="Items/DoSomethingCmd" /> 
      <Binding Path="DisabledCmd" /> 
     </PriorityBinding> 
    </Button.Command> 
</Button> 

は.cs:

public class ViewModel : NotificationObject 
{ 
    ObservableCollection<Foo> _items; 

    public DelegateCommand DisabledCmd { get; private set; } 

    public ObservableCollection<Foo> Items { 
     get { return _items; } 
     set { _items = value; RaisePropertyChanged("Items"); } 
    } 

    public ViewModel() 
    { 
     DisabledCmd = new DelegateCommand(DoNothing, CantDoAnything); 
    } 

    void DoNothing() { } 
    bool CantDoAnything() 
    { 
     return false; 
    } 
} 

編集

ノートのカップル:

  1. I 私はラムダ式を使用できますが、この例のコードではわかりません。
  2. I knowどのような述語であるか。
  3. DoSomethingCmd.CanExecuteで何かをしても、現在のアイテムがないうちにアクセスするにはDoSomethingCmdが存在しないため、何か手助けをします。
  4. 質問を再集中します:DisabledCmdの使用を避けるにはどうすればよいですか?私はDoSomethingCmdのように私が探しているものではないので興味を持っていません。私はそうでなければこの質問をしません。だから私は、基本的解決策として、この答えを採用

別の編集WPF/MVVM: Disable a Button's state when the ViewModel behind the UserControl is not yet Initialized?

それはhbarckが提案まさに、私は信じている、です。

答えて

6

私はそれをakjoshiに似ていますが、DataTriggerの代わりに通常のTriggerを使用し、Button.Commandをnullにチェックします。コマンドがないボタン(特にクリックイベントハンドラがないMVVM)を無効にすることは常に意味があるので、この動作を行うために、このトリガをButtonのデフォルトスタイルに含めることも良い考えですアプリケーション全体のすべてのボタンで...ダミーコマンドを使用する理由はわかりません。

+0

標準のWPFコントロールの一部であるすべてのボタンを無効にすることはできませんか?コマンドの代わりにイベントハンドラを使用できます。 – STiLeTT

1

delegateコマンドを見ると、2番目のパラメータは、これを正確に行うことができるfuncです。私はそれほど複雑ではないのですか? あなたが例のために行う場合は、次のとき条件

<Button Command={Binding DoSomethingCommand} /> 

ボタンを自動的に無効になります:あなたは、単にこのコマンドにそのコマンドのプロパティをバインドするときには以下のように

DoSomethingCommand = new DelegateCommand(() => SampleAction,() => Items != null); 

ボタンは、無効になりますデリゲートコマンドではfalseになります。また、ボタンのIsEnabledが現在の状態を反映するように更新するよりも、条件の結果が変わる場合はDoSomethingCommand.RaiseCanExecuteChanged()に電話する必要があります。

+0

はい私はコマンドを1レベル上げることができますが、私は自分のビューモデル内の現在のアイテムを追跡しなければならないことを知っています。 –

+0

私はViewModelの現在のアイテムをプラスしていると言います。 – cordialgerm

+0

@pickles:yes私は、現在のアイテムを間接的に 'IsSelected'で追跡しますが、WPF UIがビューレベルで既にそれをしていなければ、これを特定のプロパティにしたくありません。 –

1

RelayCommandsを使用しました。これは、canExecute Predicateを作成できるコンストラクタがあり、falseを返した場合、バインドされたボタンは自動的に無効になります。

delegateコマンドでは、CantDoAnything()メソッドを書き換えて、イネーブルおよびディセーブルロジックを表す必要があります。バインディングは単にコマンドにバインドするだけです。 PresentationFramework.dllのコードを見てみると

DelegateCommand constructor on MSDN

DelegateCommand CanExecute BugFix

+2

現在のアイテムが存在しないため、どのように述語にアクセスしますか? –

+0

@ルド述語は、実行可能かどうかをコマンドに伝えます。基本的には、コマンドがボタンにバインドされたときに実行される第2の方法です。コレクションが変更された場合は、コマンドのraisecanexecutechangeを呼び出すことができます。またはNotifyPropertyChangedも使用できると思います。 – BigL

+1

@ルドあなたのコマンドのCanExecute部分を書いて、Itemが存在しない場合にfalseを返すと、あなたのボタンはとても簡単にディアブルされます。 – BigL

3

、私は(ButtonBase.UpdateCanExecuteを参照)、それを行うための任意の簡単な方法が表示されません。 Buttonからクラスを派生させ、変更を自分で処理するためにCommandPropertyのメタデータをオーバーライドする運があるかもしれません。しかし、あなたはviewmodelでdo-nothing-commandコードを簡単に避けることができます:nullコマンドを常時無効な共有フォールバックICommandに変換する特別なコンバータを作成します。このような振る舞いを必要とするボタンがたくさんある場合、添付されたプロパティとスタイルが順番に並んでいる可能性があります。

+0

+1私はちょうど私の編集で示されているように 'NullToFalseConverter'アプローチを考え出しました。 –

+0

これは、私が示唆しているところとは少し違っています。あなたは 'Command'に加えて' IsEnabled'をバインドしていますが、コンバーターを書いて、このコンバーターで 'Command'をバインドすることができます。それでも、あなたのアプローチはもっと簡単です - 何かのために 'IsEnabled'が必要になるまで –

+0

Oこれは、スタティックリソースをfallbackコマンドとして定義して再利用できるようにすることを意味します。はい、それは改善のように聞こえる、私はあなたが何かに 'IsEnabled'をバインドする必要があると言う場合、回避策としてそれを覚えています。 –

1

ボタンのIsEnabledプロパティを現在のアイテムにバインドし、コンバータを使用するだけで済みます。 - RelayCommand MVVMライトから

public class NoCurrentItemViewModel 
{ 
    public NoCurrentItemViewModel() 
    { 
     _items = new ObservableCollection<NoCurrentItemDetail> 
        { 
         new NoCurrentItemDetail{Name = "one"}, 
         new NoCurrentItemDetail{Name = "two"}, 
        }; 

     ClearCommand = new RelayCommand(Clear); 
    } 

    public ICommand ClearCommand { get; private set; } 

    private void Clear() 
    { 
     _items.Clear(); 
    } 

    private readonly ObservableCollection<NoCurrentItemDetail> _items; 

    public IEnumerable<NoCurrentItemDetail> Items 
    { 
     get { return _items; } 
    } 
} 

public class NoCurrentItemDetail 
{ 
    public NoCurrentItemDetail() 
    { 
     DoSomethingCommand = new RelayCommand(DoSomething); 
    } 

    private void DoSomething() 
    { 
     Debug.WriteLine("Do something: " + Name); 
    } 

    public ICommand DoSomethingCommand { get; private set; } 

    public string Name { get; set; } 
} 

コンバータアイテムかどうかをチェックするためにTriggerを作成することができます

public class NullToBoolConverter : IValueConverter 
{ 
    public NullToBoolConverter() 
    { 
     IsNullValue = true; 
     IsNotNullValue = false; 
    } 

    public bool IsNullValue { get; set; } 
    public bool IsNotNullValue { get; set; } 

    #region Implementation of IValueConverter 

    public object Convert(object value, 
     Type targetType, object parameter, CultureInfo culture) 
    { 
     return value == null ? IsNullValue : IsNotNullValue; 
    } 

    public object ConvertBack(object value, 
     Type targetType, object parameter, CultureInfo culture) 
    { 
     return Binding.DoNothing; 
    } 

    #endregion 
} 
4

<Page.Resources> 
    <Converters:NullToBoolConverter x:Key="NullToBoolConverter" 
            IsNullValue="False" IsNotNullValue="True" /> 
</Page.Resources> 

<Page.DataContext> 
    <Samples:NoCurrentItemViewModel/> 
</Page.DataContext> 

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition /> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
    </Grid.RowDefinitions> 

    <ListBox 
     IsSynchronizedWithCurrentItem="True" Grid.Row="0" 
     ItemsSource="{Binding Items}" 
     DisplayMemberPath="Name"/> 

    <Button 
     Grid.Row="1" 
     Content="Do something" 
     IsEnabled="{Binding Items/, Converter={StaticResource NullToBoolConverter}}" 
     Command="{Binding Items/DoSomethingCommand}"/> 

    <Button Grid.Row="2" Content="Clear" Command="{Binding ClearCommand}"/> 
</Grid> 

ビューモデル:ここで

は完全なデモですボタンのデータコンテキスト)がnullで、Buttonを設定します(または、親コンテナのA

<DataTrigger 
    Binding="{Binding Path=Item}" 
    Value="{x:Null}"> 
    <Setter Property="Control.IsEnabled" Value="False" /> 
</DataTrigger> 

私は今それをテストする立場にありませんが、私は、これは動作するはずだと思う - NTONは、falseに)このようなものをIsEnabled性質を述べました。

関連する問題