WPF MVVM实现:点击按钮增减DataGrid单元格数值
实现DataGrid单元格数值的加减按钮功能
没问题,这是WPF MVVM开发里非常常见的场景,我来一步步带你实现这个加减数值的功能:
第一步:完善模型与ViewModel,实现属性变更通知
WPF的UI更新依赖INotifyPropertyChanged接口,所以你的ProductModel和ViewModel都需要实现这个接口,否则属性变化后UI不会自动刷新。
补全ProductModel代码
public class ProductModel : INotifyPropertyChanged { private decimal _productQuantity; public decimal Product_Quantity { get => _productQuantity; set { if (_productQuantity != value) { _productQuantity = value; OnPropertyChanged(nameof(Product_Quantity)); } } } // 这里放你的其他属性... public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
完善ViewModel(添加命令+补全属性)
我们需要给ViewModel添加加减命令,同时补全SelectedRow的setter并实现属性变更通知:
public class YourViewModel : INotifyPropertyChanged { private ObservableCollection<ProductModel> _products; public ObservableCollection<ProductModel> Products { get => _products; set { _products = value; OnPropertyChanged(nameof(Products)); } } private ProductModel _selectedRow; public ProductModel SelectedRow { get => _selectedRow; set { _selectedRow = value; OnPropertyChanged(nameof(SelectedRow)); } } // 加减命令 public ICommand IncrementCommand { get; } public ICommand DecrementCommand { get; } public YourViewModel() { Products = new ObservableCollection<ProductModel>(); // 初始化命令(如果没用MVVM框架,就用下面的自定义RelayCommand) IncrementCommand = new RelayCommand(ExecuteIncrement, CanExecuteModify); DecrementCommand = new RelayCommand(ExecuteDecrement, CanExecuteModify); } private void ExecuteIncrement() { if (SelectedRow != null) { SelectedRow.Product_Quantity += 1; } } private void ExecuteDecrement() { // 可以加个最小值限制,比如不能小于0 if (SelectedRow != null && SelectedRow.Product_Quantity > 0) { SelectedRow.Product_Quantity -= 1; } } // 控制命令是否可用(只有选中行时按钮才可用) private bool CanExecuteModify() { return SelectedRow != null; } // INotifyPropertyChanged实现 public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
自定义RelayCommand(如果没使用MVVM框架)
如果你的项目没用到Prism、MVVM Light这类框架,需要自己实现一个简单的RelayCommand来支持命令绑定:
public class RelayCommand : ICommand { private readonly Action _execute; private readonly Func<bool> _canExecute; public RelayCommand(Action execute, Func<bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(); } public void Execute(object parameter) { _execute(); } }
第二步:XAML实现(两种方案任选)
方案一:每行都带加减按钮(嵌入DataGrid列)
如果想让DataGrid的每一行都有自己的加减按钮,可以用DataGridTemplateColumn来实现:
<DataGrid ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedRow}" AutoGenerateColumns="False"> <DataGrid.Columns> <!-- 其他业务列 --> <DataGridTextColumn Header="商品数量" Binding="{Binding Product_Quantity}" /> <DataGridTemplateColumn Header="操作"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Spacing="5"> <Button Content="+" Command="{Binding DataContext.IncrementCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" CommandParameter="{Binding}" /> <Button Content="-" Command="{Binding DataContext.DecrementCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" CommandParameter="{Binding}" /> </StackPanel> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
这种情况下,需要把ViewModel的命令改成支持参数的泛型版本,调整一下:
// 修改ViewModel的命令初始化 IncrementCommand = new RelayCommand<ProductModel>(ExecuteIncrementWithParam); DecrementCommand = new RelayCommand<ProductModel>(ExecuteDecrementWithParam); // 对应的执行方法 private void ExecuteIncrementWithParam(ProductModel product) { product.Product_Quantity += 1; } private void ExecuteDecrementWithParam(ProductModel product) { if (product.Product_Quantity > 0) { product.Product_Quantity -= 1; } } // 泛型版RelayCommand public class RelayCommand<T> : ICommand { private readonly Action<T> _execute; private readonly Predicate<T> _canExecute; public RelayCommand(Action<T> execute, Predicate<T> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute((T)parameter); } public void Execute(object parameter) { _execute((T)parameter); } }
方案二:全局加减按钮(操作选中行)
如果只需要页面上的全局按钮来操作当前选中的行,XAML会更简单:
<StackPanel Margin="10"> <StackPanel Orientation="Horizontal" Spacing="10" Margin="0 0 0 10"> <Button Content="增加数量" Command="{Binding IncrementCommand}"/> <Button Content="减少数量" Command="{Binding DecrementCommand}"/> </StackPanel> <DataGrid ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedRow}" AutoGenerateColumns="True"/> </StackPanel>
这个方案直接用第一步里的非参数版命令即可,没有选中行时按钮会自动灰掉。
关键注意点
- 必须实现
INotifyPropertyChanged:这是WPF UI自动更新的核心,模型和ViewModel的属性变更都要触发PropertyChanged事件。 - 用
ICommand实现逻辑分离:MVVM模式下尽量避免在代码后台直接操作UI,通过命令绑定把业务逻辑放在ViewModel里。 - 命令的可执行状态:通过
CanExecute方法控制按钮的可用状态,提升用户体验。
内容的提问来源于stack exchange,提问作者Usman Ali
相关产品推荐
相关产品推荐

