【问题标题】:Move Focus to Next Cell on Enter Key Press in WPF DataGrid?在WPF DataGrid中按Enter键时将焦点移动到下一个单元格?
【发布时间】:2012-05-11 09:24:41
【问题描述】:

我想要一个自定义的DataGrid,可以,

  1. 如果处于编辑模式,按下 Enter 键时移动到下一个单元格。
  2. 到达当前行的最后一列时,焦点应移至下一行的第一个单元格。
  3. 到达下一个单元格时,如果该单元格是可编辑的,它应该会自动变为可编辑。
  4. 如果单元格包含 ComboBox 而不是组合框列,则组合框应 DropDownOpen。​​

请帮助我。从过去的几天开始,我一直在尝试创建一个自定义 DataGrid 并在

中编写了一些代码
protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)

但我失败了。

【问题讨论】:

    标签: c# wpf mvvm wpfdatagrid


    【解决方案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
      

      【讨论】:

        猜你喜欢
        • 2019-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-22
        • 1970-01-01
        • 2023-02-15
        • 1970-01-01
        相关资源
        最近更新 更多