在WPF DataGrid中按Enter键时将焦点移动到下一个单元格?
Posted
技术标签:
【中文标题】在WPF DataGrid中按Enter键时将焦点移动到下一个单元格?【英文标题】:Move Focus to Next Cell on Enter Key Press in WPF DataGrid? 【发布时间】:2012-05-11 09:24:41 【问题描述】:我想要一个自定义的DataGrid,可以,
-
如果处于编辑模式,按下 Enter 键时移动到下一个单元格。
到达当前行的最后一列时,焦点应移至下一行的第一个单元格。
到达下一个单元格时,如果该单元格是可编辑的,它应该会自动变为可编辑。
如果单元格包含
ComboBox
而不是组合框列,则组合框应 DropDownOpen。
请帮助我。从过去的几天开始,我一直在尝试创建一个自定义 DataGrid 并在
中编写了一些代码protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
但我失败了。
【问题讨论】:
【参考方案1】:一个更简单的实现。这个想法是捕获 keydown 事件,如果键是“Enter”,则移动到下一个选项卡,即网格的下一个单元格。
/// <summary>
/// On Enter Key, it tabs to into next cell.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataGrid_OnPreviewKeyDown(object sender, KeyEventArgs e)
var uiElement = e.OriginalSource as UIElement;
if (e.Key == Key.Enter && uiElement != null)
e.Handled = true;
uiElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
【讨论】:
我在使用您的代码时遇到的问题是我有多个DataGridTemplateColumn
每个内部都有一个文本框...代码将焦点移到下一个单元格/文本框,但不完全是,我的意思是文本框得到外部黑点/线条。我必须按两次 Enter 才能完全专注于下一个单元格/文本框...有什么解决办法吗?【参考方案2】:
private void dg_PreviewKeyDown(object sender, KeyEventArgs e)
try
if (e.Key == Key.Enter)
e.Handled = true;
var cell = GetCell(dgIssuance, dgIssuance.Items.Count - 1, 2);
if (cell != null)
cell.IsSelected = true;
cell.Focus();
dg.BeginEdit();
catch (Exception ex)
MessageBox(ex.Message, "Error", MessageType.Error);
public static DataGridCell GetCell(DataGrid dg, int row, int column)
var rowContainer = GetRow(dg, row);
if (rowContainer != null)
var presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
if (presenter != null)
// try to get the cell but it may possibly be virtualized
var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
// now try to bring into view and retreive the cell
dg.ScrollIntoView(rowContainer, dg.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
return cell;
return null;
【讨论】:
我在几个项目中做过类似的事情,代码非常非常相似。我只是扩展了数据网格并封装了你在其中所做的大部分工作。所以我可以保证这个/你的答案绝对有效! +1 很高兴看到缺少的代码:GetRow()
、GetVisualChild<T>()
以及 dgIssuance
是什么?
为什么要将硬编码值传递给 GetCell 函数???问题是关于在按下 Enter 键时移动到 next 单元格,但是您试图在 Enter 单击时获取第二列中的最后一个单元格。为什么?【参考方案3】:
这个解决方案怎么样?通过设置Handled=true
取消Enter键的动作并按下Tab键。
public Constructor()
InitializeComponent();
this.SampleDataGrid.PreviewKeyDown += MoveCellOnEnterKey;
private void MoveCellOnEnterKey(object sender, KeyEventArgs e)
if(e.Key == Key.Enter)
// Cancel [Enter] key event.
e.Handled = true;
// Press [Tab] key programatically.
var tabKeyEvent = new KeyEventArgs(
e.KeyboardDevice, e.InputSource, e.Timestamp, Key.Tab);
tabKeyEvent.RoutedEvent = Keyboard.KeyDownEvent;
InputManager.Current.ProcessInput(tabKeyEvent);
【讨论】:
【参考方案4】:public class DataGrid : System.Windows.Controls.DataGrid
private void PressKey(Key key)
KeyEventArgs args = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, key);
args.RoutedEvent = Keyboard.KeyDownEvent;
InputManager.Current.ProcessInput(args);
protected override void OnCurrentCellChanged(EventArgs e)
if (this.CurrentCell.Column != null)
if (this.CurrentCell.Column.DisplayIndex == 2)
if (this.CurrentCell.Item.ToString() == "--End Of List--")
this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
else if (this.CurrentCell.Column != null && this.CurrentCell.Column.DisplayIndex == this.Columns.Count() - 1)
PressKey(Key.Return);
DataGridCell cell = DataGridHelper.GetCell(this.CurrentCell);
int index = DataGridHelper.GetRowIndex(cell);
DataGridRow dgrow = (DataGridRow)this.ItemContainerGenerator.ContainerFromItem(this.Items[index]);
dgrow.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
protected override void OnKeyDown(KeyEventArgs e)
if (e.Key == Key.Enter)
DataGridRow rowContainer = (DataGridRow)this.ItemContainerGenerator.ContainerFromItem(this.CurrentItem);
if (rowContainer != null)
int columnIndex = this.Columns.IndexOf(this.CurrentColumn);
DataGridCellsPresenter presenter = UIHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer);
if (columnIndex == 0)
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
request.Wrapped = true;
cell.MoveFocus(request);
BeginEdit();
PressKey(Key.Down);
else
CommitEdit();
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
request.Wrapped = true;
cell.MoveFocus(request);
this.SelectedItem = this.CurrentItem;
e.Handled = true;
this.UpdateLayout();
目前,我已经写了这个并且它为我工作。
【讨论】:
我收到错误“错误 137 找不到类型“my:DataGridComboBoxColumn”。确认您没有丢失程序集引用并且所有引用的程序集都已构建。当我扩展 datagrid 类时出现错误【参考方案5】: Public Sub SendKey(ByVal key As Key)
Dim args As New KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, key)
args.RoutedEvent = Keyboard.KeyDownEvent
InputManager.Current.ProcessInput(args)
End Sub
Private Sub dataGrid_PreviewKeyDown(sender As Object, e As KeyEventArgs) Handles dataGrid.PreviewKeyDown
Dim i As UIElement = e.OriginalSource
Dim DG As DataGrid = sender
If (e.Key = Key.Enter Or e.Key = Key.Return) AndAlso i IsNot Nothing Then
MyBase.OnKeyDown(e)
DG.CommitEdit()
SendKey(Key.Tab)
e.Handled = True
End If
End Sub
【讨论】:
以上是关于在WPF DataGrid中按Enter键时将焦点移动到下一个单元格?的主要内容,如果未能解决你的问题,请参考以下文章
WPF:一个文本框,它具有在按下 Enter 键时触发的事件
在 URL 包含“#”的地址栏中按下 Enter 键时的行为