この問題は、複数のビューモデルクラスが含まれているため、少し毛深いものです。これを解決するコードには亀裂があります。私が紛失している唯一の事は、行を離れるまで、DataGridがアイテムを更新しないように見えることです。

XAML:
<button Content="{Binding Path=SelectedTestCount}"
Command="{Binding SaveCommand}"
Grid.Row="1" Width="75" Height="23"
HorizontalAlignment="Right" Margin="0,0,6,6"/>
シングクラス:
public class Thing : INotifyPropertyChanged
{
private readonly List selectableThings;
private DelegateCommand saveCommand;
public Thing(IEnumerable selectableThings)
{
this.selectableThings = new List(selectableThings);
this.SelectableThings =
new ObservableCollection(this.selectableThings);
this.SaveCommand = this.saveCommand = new DelegateCommand(
o => Save(),
o => SelectableThings.Any(t => t.IsSelected)
);
//Bind children to change event
foreach (var selectableThing in this.selectableThings)
{
selectableThing.PropertyChanged += SelectableThingChanged;
}
SelectableThings.CollectionChanged += SelectableThingsChanged;
}
public ObservableCollection SelectableThings
{
get;
private set;
}
public int SelectedTestCount
{
get { return SelectableThings.Where(t => t.IsSelected).Count(); }
}
public ICommand SaveCommand { get; private set; }
private void Save()
{
//Todo: Implement
}
private void SelectableThingChanged(object sender,
PropertyChangedEventArgs args)
{
if (args.PropertyName == "IsSelected")
{
RaisePropertyChanged("SelectedTestCount");
saveCommand.RaiseCanExecuteChanged();
}
}
private void SelectableThingsChanged(object sender,
NotifyCollectionChangedEventArgs e)
{
foreach (SelectableThing selectableThing in
e.OldItems ?? new List())
{
selectableThing.PropertyChanged -= SelectableThingChanged;
RaisePropertyChanged("SelectedTestCount");
}
foreach (SelectableThing selectableThing in
e.NewItems ?? new List())
{
selectableThing.PropertyChanged += SelectableThingChanged;
RaisePropertyChanged("SelectedTestCount");
}
}
public void RaisePropertyChanged(string propertyName)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Selectableシングクラス:
public class SelectableThing : INotifyPropertyChanged
{
private string name;
private bool isSelected;
public SelectableThing(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
set
{
name = value;
RaisePropertyChanged("Name");
}
}
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
元の回答:
Command
を ICommand
にバインドします。あなたの条件が満たされていないときに false
を返すように ICommand
に CanExecute
を設定します。
その IsSelected
プロパティの設定で、値が変更されたら CanExecuteChanged
イベントを発生させます。
Button
の Command
バインディングは、 CanExecute
の結果に基づいて自動的にボタンを有効/無効にします。
ここで使用できる ICommand
の実装など、これを行う方法の詳細については、このミニMVVMチュートリアル別の質問のために書きました。
CanExecute
の実装を記入するには、Linqの .Any
メソッドのようなものを使用します。次に、 Count
のチェックを気にする必要はなく、チェックされているアイテムがあれば早期にループを終了させることができます。
例えば:
this.SaveCommand = new DelegateCommand(Save, CanSave);
// ...
private void Save(object unusedArg)
{
//Todo: Implement
}
private bool CanSave(object unusedArg)
{
return SelectableThings.Any(t => t.IsSelected);
}
または短いので、ラムダインラインを使用します。
this.SaveCommand = new DelegateCommand(Save,
o => SelectableThings.Any(t => t.IsSelected)
);