在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&lt;T&gt;() 以及 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键时将焦点移动到下一个单元格?的主要内容,如果未能解决你的问题,请参考以下文章

在 VC6-MFC 中按 ENTER 键时的 TAB 效果

WPF:一个文本框,它具有在按下 Enter 键时触发的事件

当我在文本框中按 Enter 键时发出恼人的哔哔声

在 URL 包含“#”的地址栏中按下 Enter 键时的行为

当我们从文本框中按 Enter 键时,在单个 jQuery 方法中处理多个操作

当根据文本框的焦点按下 Enter 键时,如何触发 Button Click 事件?