WPF可编辑DataGrid双向绑定:实现回车键触发值绑定需求
在WPF DataGrid中按下回车键立即更新双向绑定的解决方案
这个问题我做WPF项目时也碰到过,默认的DataGridCell非得失去焦点才会触发双向绑定更新,对用户来说确实有点麻烦。下面给你几个亲测有效的解决方案,按需选就行:
方案1:使用Blend行为(Behavior)实现(推荐,解耦性强)
这种方式通过附加行为来处理回车键事件,不需要修改原有列的类型,复用性很高。
步骤:
首先确保你的项目引用了行为库:
- .NET Framework:引用
System.Windows.Interactivity(可以通过NuGet安装Microsoft.Expression.Interactions) - .NET Core/.NET 5+:安装NuGet包
Microsoft.Xaml.Behaviors.Wpf
- .NET Framework:引用
创建自定义行为类:
using Microsoft.Xaml.Behaviors.Wpf; using System.Windows; using System.Windows.Controls; using System.Windows.Input; public class UpdateBindingOnEnterBehavior : Behavior<DataGridCell> { protected override void OnAttached() { base.OnAttached(); // 监听单元格的预览按键事件 AssociatedObject.PreviewKeyDown += OnPreviewKeyDown; } protected override void OnDetaching() { // 记得移除事件,避免内存泄漏 AssociatedObject.PreviewKeyDown -= OnPreviewKeyDown; base.OnDetaching(); } private void OnPreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key != Key.Enter) return; var cell = sender as DataGridCell; if (cell == null || !cell.IsEditing) return; // 提交单元格编辑,触发绑定源更新 cell.CommitEdit(); // 如果需要自动聚焦到下一个单元格,取消注释下面两行 // var traversalRequest = new TraversalRequest(FocusNavigationDirection.Next); // cell.MoveFocus(traversalRequest); e.Handled = true; // 阻止事件冒泡 } }
- 在XAML中使用该行为:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding YourItemCollection}"> <DataGrid.Columns> <DataGridTextColumn Header="Quantity" Binding="{Binding Quantity, UpdateSourceTrigger=LostFocus}"> <DataGridTextColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="behaviors:Interaction.Behaviors"> <Setter.Value> <local:UpdateBindingOnEnterBehavior /> </Setter.Value> </Setter> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> <!-- 其他列配置 --> </DataGrid.Columns> </DataGrid>
注意:XAML中需要添加命名空间
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"和自定义类的命名空间xmlns:local="clr-namespace:YourProjectNamespace"
方案2:自定义DataGridTextColumn
如果你想直接针对特定列做定制,可以继承DataGridTextColumn,重写编辑元素的生成逻辑,添加回车键处理。
using System.Windows; using System.Windows.Controls; using System.Windows.Input; public class AutoUpdateTextColumn : DataGridTextColumn { protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { var textBox = base.GenerateEditingElement(cell, dataItem) as TextBox; if (textBox != null) { textBox.KeyDown += TextBox_KeyDown; } return textBox; } private void TextBox_KeyDown(object sender, KeyEventArgs e) { if (e.Key != Key.Enter) return; var textBox = sender as TextBox; if (textBox == null) return; // 直接更新绑定源 var bindingExpr = textBox.GetBindingExpression(TextBox.TextProperty); bindingExpr?.UpdateSource(); // 结束单元格编辑 var cell = textBox.Parent as DataGridCell; cell?.CommitEdit(); e.Handled = true; } }
在XAML中直接使用这个自定义列:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding YourItemCollection}"> <DataGrid.Columns> <local:AutoUpdateTextColumn Header="Quantity" Binding="{Binding Quantity}" /> <!-- 其他列 --> </DataGrid.Columns> </DataGrid>
方案3:附加属性实现全局处理
如果想让整个DataGrid的所有可编辑列都支持回车更新,可以用附加属性来全局配置:
using System.Windows; using System.Windows.Controls; using System.Windows.Input; public static class DataGridHelper { public static readonly DependencyProperty UpdateBindingOnEnterProperty = DependencyProperty.RegisterAttached( "UpdateBindingOnEnter", typeof(bool), typeof(DataGridHelper), new PropertyMetadata(false, OnUpdateBindingOnEnterChanged)); public static bool GetUpdateBindingOnEnter(DependencyObject obj) { return (bool)obj.GetValue(UpdateBindingOnEnterProperty); } public static void SetUpdateBindingOnEnter(DependencyObject obj, bool value) { obj.SetValue(UpdateBindingOnEnterProperty, value); } private static void OnUpdateBindingOnEnterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var dataGrid = d as DataGrid; if (dataGrid == null) return; if ((bool)e.NewValue) { dataGrid.PreviewKeyDown += DataGrid_PreviewKeyDown; } else { dataGrid.PreviewKeyDown -= DataGrid_PreviewKeyDown; } } private static void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key != Key.Enter) return; var dataGrid = sender as DataGrid; var cell = dataGrid.CurrentCell.Item as DataGridCell; if (cell != null && cell.IsEditing) { cell.CommitEdit(); e.Handled = true; } } }
XAML中使用:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding YourItemCollection}" local:DataGridHelper.UpdateBindingOnEnter="True"> <!-- 列配置 --> </DataGrid>
内容的提问来源于stack exchange,提问作者Sarathi Jayapal
相关产品推荐
相关产品推荐

