2012-11-28 55 views
2

我的數據網格存在一些問題。我的項目正在將一個Delphi項目轉變爲.Net。產品所有者需要與數據網格相同的行爲。Tab創建新行並將焦點放在DataGrid中的新行

當位於最後一個單元格和標籤或輸入被擊中,下面應該發生:

  1. 一個新行添加
  2. 新行中的第一個單元格選定

爲DataGrid的其他要求是:

  • 重點應保持在數據網格中,一旦有focu s(ALT +組合鍵是再次離開數據網格的方式)。
  • 數據網格一個數據綁定
  • 數據網格在MVVM
  • 使用我們使用.net4.0完整的個人資料
+0

我嘗試用KeyboardNavigation.TabNavigation =「Contained」和KeyboardNavigation.TabNavigation的其他值進行操作。我不能找到組合。我所有的嘗試要麼從數據網格中跳出來,要麼不會創建新的線。 在我看來,我需要一些其他技術來調整datagrid,我還沒有找到。 – Rokke

回答

2

This article了我能找到最佳的解決方案。

我更喜歡使用附加屬性而不是行爲,因爲這使我能夠以DataGrid的默認樣式輕鬆設置它。下面的代碼:

namespace SampleDataGridApp 
{ 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Input; 

    /// <summary> 
    /// An attached behavior that modifies the tab behavior for a <see cref="DataGrid"/>. 
    /// </summary> 
    public static class DataGridBehavior 
    { 
     /// <summary> 
     /// Identifies the <c>NewLineOnTab</c> attached property. 
     /// </summary> 
     public static readonly DependencyProperty NewLineOnTabProperty = DependencyProperty.RegisterAttached(
      "NewLineOnTab", 
      typeof(bool), 
      typeof(DataGridBehavior), 
      new PropertyMetadata(default(bool), OnNewLineOnTabChanged)); 

     /// <summary> 
     /// Sets the value of the <c>NewLineOnTab</c> attached property. 
     /// </summary> 
     /// <param name="element">The <see cref="DataGrid"/>.</param> 
     /// <param name="value">A value indicating whether to apply the behavior.</param> 
     public static void SetNewLineOnTab(DataGrid element, bool value) 
     { 
      element.SetValue(NewLineOnTabProperty, value); 
     } 

     /// <summary> 
     /// Gets the value of the <c>NewLineOnTab</c> attached property. 
     /// </summary> 
     /// <param name="element">The <see cref="DataGrid"/>.</param> 
     /// <returns>A value indicating whether to apply the behavior.</returns> 
     public static bool GetNewLineOnTab(DataGrid element) 
     { 
      return (bool)element.GetValue(NewLineOnTabProperty); 
     } 

     /// <summary> 
     /// Called when the value of the <c>NewLineOnTab</c> property changes. 
     /// </summary> 
     /// <param name="sender">The event sender.</param> 
     /// <param name="e">The event arguments.</param> 
     private static void OnNewLineOnTabChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
     { 
      DataGrid d = sender as DataGrid; 

      if (d == null) 
      { 
       return; 
      } 

      bool newValue = (bool)e.NewValue; 
      bool oldValue = (bool)e.OldValue; 

      if (oldValue == newValue) 
      { 
       return; 
      } 

      if (oldValue) 
      { 
       d.PreviewKeyDown -= AssociatedObjectKeyDown; 
      } 
      else 
      { 
       d.PreviewKeyDown += AssociatedObjectKeyDown; 
       KeyboardNavigation.SetTabNavigation(d, KeyboardNavigationMode.Contained); 
      } 
     } 

     /// <summary> 
     /// Handles the <see cref="UIElement.KeyDown"/> event for a <see cref="DataGridCell"/>. 
     /// </summary> 
     /// <param name="sender">The event sender.</param> 
     /// <param name="e">The event arguments.</param> 
     private static void AssociatedObjectKeyDown(object sender, KeyEventArgs e) 
     { 
      if (e.Key != Key.Tab) 
      { 
       return; 
      } 

      DataGrid dg = e.Source as DataGrid; 

      if (dg == null) 
      { 
       return; 
      } 

      if (dg.CurrentColumn.DisplayIndex == dg.Columns.Count - 1) 
      { 
       var icg = dg.ItemContainerGenerator; 

       if (dg.SelectedIndex == icg.Items.Count - 2) 
       { 
        dg.CommitEdit(DataGridEditingUnit.Row, false); 
       } 
      } 
     } 
    } 
} 

我的默認樣式看起來是這樣的:

<Style TargetType="DataGrid"> 
    <Setter Property="GridLinesVisibility" Value="None" /> 
    <Setter Property="KeyboardNavigation.TabNavigation" Value="Contained" /> 
    <Setter Property="sampleDataGridApp:DataGridBehavior.NewLineOnTab" Value="True" /> 
    <Setter Property="IsSynchronizedWithCurrentItem" Value="True" /> 
</Style> 

如果最後一列的DataGridCell有它IsTabStop設置爲false像this example上面將無法工作。

這裏是一個有錯誤的解決方法:

private static void AssociatedObjectKeyDown(object sender, KeyEventArgs e) 
{    
    if (e.Key != Key.Tab) 
    { 
     return; 
    } 

    DataGrid dg = e.Source as DataGrid; 

    if (dg == null) 
    { 
     return; 
    } 

    int offSet = 1; 
    var columnsReversed = dg.Columns.Reverse(); 
    foreach (var dataGridColumn in columnsReversed) 
    { 
     // Bug: This makes the grand assumption that a readonly column's "DataGridCell" has IsTabStop == false; 
     if (dataGridColumn.IsReadOnly) 
     { 
      offSet++; 
     } 
     else 
     { 
      break; 
     } 
    } 

    if (dg.CurrentColumn.DisplayIndex == (dg.Columns.Count - offSet)) 
    { 
     var icg = dg.ItemContainerGenerator; 

     if (dg.SelectedIndex == icg.Items.Count - 2) 
     { 
      dg.CommitEdit(DataGridEditingUnit.Row, false); 
     } 
    } 
} 
0

好吧,我一直在爭取這個問題好幾個小時。我已經試過幾乎所有提出的解決方案在那裏,這裏是我發現對我的作品......

private void grid_PreviewKeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.Key == Key.Tab) 
     { 
      if (grid.SelectedIndex == grid.Items.Count - 2 && grid.CurrentColumn.DisplayIndex == grid.Columns.Count - 1) 
      { 
       grid.CommitEdit(DataGridEditingUnit.Row, false); 
       e.Handled = true; 
      } 
     } 
    } 

    private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) 
    { 
     if (grid.SelectedIndex == grid.Items.Count - 2) 
     { 
      grid.SelectedIndex = grid.Items.Count - 1; 
      grid.CurrentCell = new DataGridCellInfo(grid.Items[grid.Items.Count - 1], grid.Columns[0]); 
     } 
    } 

這段代碼的作用是,當您選項卡的最後一行,然後按Tab它會的最後一個單元格將焦點移至新行的第一個單元格。這是你所期望的,但這不是默認行爲。默認行爲是將焦點移動到下一個控件並且不提交當前行編輯。這顯然是DataGrid中的一個錯誤,我相信這就是爲什麼所有提出的解決方案都有一絲苦差。我的解決方案沒有聞到我承認的那麼好,但如果你同意這是錯誤,我更喜歡這種可笑的默認行爲。

該解決方案即使在網格排序後也能正常工作。新輸入的行將排序到適當的位置,但重點將放在新行的第一列。

唯一未解決的問題是,當在新行之前從頂部切換到最後一個單元格時,必須在焦點移動到新行之前輸入兩次製表符。我看了一下這個怪癖,最後放棄了。

相關問題