如何在WPF中启用/禁用按钮?
我有一个相对简单的WPF应用程序。其思想是向用户呈现项目列表;对于每个项目,都有一个复选框用于选择/取消选择该项目 我的简化代码看起来有点像这样:如何在WPF中启用/禁用按钮?,wpf,Wpf,我有一个相对简单的WPF应用程序。其思想是向用户呈现项目列表;对于每个项目,都有一个复选框用于选择/取消选择该项目 我的简化代码看起来有点像这样: class Thing { /* ... */ }; public static int SelectedCount { get; set; } public class SelectableThing { private bool _selected; public bool Selected {
class Thing { /* ... */ };
public static int SelectedCount { get; set; }
public class SelectableThing
{
private bool _selected;
public bool Selected {
get { return _selected; }
set { _selected = value; if (value) { SelectedCount++; } else { SelectedCount--; } }
}
public Thing thing { get; set; }
};
private ObservableCollection<SelectableThing> _selectableThings;
public Collection<SelectableThing> { get { return _selectableThings; } }
<DataGrid ItemSource="{Binding Path=SelectableThings}">
<DataGridCheckBoxColumn Binding="{Binding Selected}"/>
<DataGridTextColumn Binding="{Binding Thing.name}"/>
</DataGrid>
<Button Content="{Binding Path=SelectedTestCount}" Click="someFunc" />
类事物{/*…*/};
公共静态int-SelectedCount{get;set;}
公共类可选择事物
{
选择私人布尔;
已选择公共布尔值{
获取{return\u selected;}
设置{u selected=value;如果(value){SelectedCount++;}否则{SelectedCount--;}
}
公共事物{get;set;}
};
私人可观察收集(可选择的事物);;
公共集合{get{return\u selectableThings;}
因此,这个想法是按钮内容应该显示所选测试的计数。这应该实现,因为无论何时设置SelectableThing.Selected,它都应该根据需要增加/减少SelectedCount
然而,据我所知,这种行为不起作用。无论选择/取消选择列表中的项目,按钮文本均显示“0”
有什么想法吗?将按钮的内容绑定到viewmodel中的某个字段,并在每次选择或取消选择另一项时为该字段触发OnChanged方法。将IsEnabled绑定到视图模型中的布尔字段,并根据需要将其设置为true/false以启用或禁用按钮。由于涉及多个视图模型类,因此此问题有点棘手。这里有一个破解代码来解决这个问题。我唯一缺少的是DataGrid似乎在您离开该行之前不会更新您的项目 XAML: 原始答案: 将
命令
绑定到ICommand
。将i命令上的CanExecute
设置为在条件不满足时返回false
在该IsSelected
属性的setter中,当值更改时,引发CanExecuteChanged
事件
按钮上的命令
绑定
会根据CanExecute
的结果自动启用/禁用按钮
有关如何执行此操作的更多信息,包括可以在此处使用的ICommand
的实现,请参阅我撰写的另一个问题
为了填写CanExecute
的实现,我会使用类似Linq的。Any
方法。这样,您就不必费心检查计数
,如果您发现任何项目都已检查,则可以提前终止循环
例如:
this.SaveCommand = new DelegateCommand(Save, CanSave);
// ...
private void Save(object unusedArg)
{
// Todo: Implement
}
private bool CanSave(object unusedArg)
{
return SelectableThings.Any(t => t.IsSelected);
}
或者,由于它很短,请使用lambda内联:
this.SaveCommand = new DelegateCommand(Save,
o => SelectableThings.Any(t => t.IsSelected)
);
基于IsSelected
更改提升CanExecuteChanged
的部分可能很棘手,因为看起来您使用的是一组子视图模型。您可以在每个上订阅INotifyPropertyChanged
,并将事件转发到this.SaveCommand.raisecancecutechanged()
。如果您在计算此部分时遇到问题,请告诉我。另外请注意,我建议您将属性命名为IsSelected
。在命名布尔值(Is、Can、Has等)时,应遵循此约定;你能告诉我你的想法吗?@StephenGross:虽然使用静态
成员可能有效,但这是一种黑客行为。您不能支持持有该属性的任何类的多个实例(Thing
?)。为这段代码编写单元测试也将更加困难。我也不确定WPF是否可以绑定到静态属性,或者INotifyPropertyChanged
是否可以使用它。是的,我使用静态int的唯一原因是,否则您无法从SelectableThing.Selected.set()内部对其进行更改。您是使用viewmodels还是只使用代码隐藏?我已经修改了原始问题来尝试这一点,但可能是弄错了。。。
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));
}
}
}
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)
);