我的數據網格存在一些問題。我的項目正在將一個Delphi項目轉變爲.Net。產品所有者需要與數據網格相同的行爲。Tab創建新行並將焦點放在DataGrid中的新行
當位於最後一個單元格和標籤或輸入被擊中,下面應該發生:
- 一個新行添加
- 新行中的第一個單元格選定
爲DataGrid的其他要求是:
- 重點應保持在數據網格中,一旦有focu s(ALT +組合鍵是再次離開數據網格的方式)。
- 數據網格一個數據綁定
- 數據網格在MVVM
- 使用我們使用.net4.0完整的個人資料
我的數據網格存在一些問題。我的項目正在將一個Delphi項目轉變爲.Net。產品所有者需要與數據網格相同的行爲。Tab創建新行並將焦點放在DataGrid中的新行
當位於最後一個單元格和標籤或輸入被擊中,下面應該發生:
爲DataGrid的其他要求是:
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);
}
}
}
好吧,我一直在爭取這個問題好幾個小時。我已經試過幾乎所有提出的解決方案在那裏,這裏是我發現對我的作品......
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中的一個錯誤,我相信這就是爲什麼所有提出的解決方案都有一絲苦差。我的解決方案沒有聞到我承認的那麼好,但如果你同意這是錯誤,我更喜歡這種可笑的默認行爲。
該解決方案即使在網格排序後也能正常工作。新輸入的行將排序到適當的位置,但重點將放在新行的第一列。
唯一未解決的問題是,當在新行之前從頂部切換到最後一個單元格時,必須在焦點移動到新行之前輸入兩次製表符。我看了一下這個怪癖,最後放棄了。
我嘗試用KeyboardNavigation.TabNavigation =「Contained」和KeyboardNavigation.TabNavigation的其他值進行操作。我不能找到組合。我所有的嘗試要麼從數據網格中跳出來,要麼不會創建新的線。 在我看來,我需要一些其他技術來調整datagrid,我還沒有找到。 – Rokke