为什么在以编程方式添加新项目后 WPF DataGridCell.Content 是 TextBlock 而不是 TextBox?
Why is a WPF DataGridCell.Content a TextBlock instead of a TextBox after adding a new item programmatically?
我想将 Excel table 中的数据复制粘贴到 WPF DataGrid
中。为此,我有以下函数,它在 KeyDown
事件中被调用:
private void OnDataGridPasteData(object sender, KeyEventArgs e)
{
if ((Keyboard.Modifiers != ModifierKeys.Control) || e.Key != Key.V)
return;
DataGrid dg = (DataGrid)sender;
var pastedData = Clipboard.GetText();
List<string> rowDataCombined = pastedData.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).ToList();
List<string[]> rowData = new List<string[]>();
foreach (var row in rowDataCombined)
{
rowData.Add(row.Split(new string[] { "\t" }, StringSplitOptions.None));
}
int initialRowIdx = Math.Max(dg.Items.IndexOf(dg.SelectedItem), 0);
int initialColIdx = dg.CurrentCell.Column.DisplayIndex;
int maxColIdx = dg.Columns.Count;
int maxRowIdx = initialRowIdx + rowData.Count;
Type sourceType = dg.ItemsSource.GetType().GetGenericArguments()[0];
var sourceList = (IList)dg.ItemsSource;
for (int r = initialRowIdx; r < maxRowIdx; r++)
{
if(r > dg.Items.Count - 1)
{
var newRowObject = Activator.CreateInstance(sourceType);
sourceList.Add(newRowObject);
}
DataGridRow dgRow = GetRowFromDataGrid(dg, r);
if (dgRow == null)
continue;
for (int c = initialColIdx; c < maxColIdx; c++)
{
var presenter = FindVisualChild<DataGridCellsPresenter>(dgRow);
// try to get the cell but it may possibly be virtualized
var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(c);
if (cell == null)
{
// now try to bring into view and retreive the cell
dg.ScrollIntoView(dgRow, dg.Columns[c]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(c);
}
if(cell != null)
{
cell.Focus();
if (!dg.BeginEdit()) //abort pasting if editing fails
{
dg.CancelEdit();
return;
}
if(cell.Content is TextBox tb)
{
tb.Text = rowData[r - initialRowIdx][c - initialColIdx];
}
if(!dg.CommitEdit()) // abort pasting if commit fails (e.g. wrong entry type)
{
dg.CancelEdit();
return;
}
}
}
}
}
注意行 if(cell.Content is TextBox tb)
:
- 对于现有的
DataGridCells
这将是 true
- 对于新添加的项目(第
sourceList.Add(newRowObject);
行),这将是错误的。那么内容类型是 TextBlock
- 如果我在进入
for
循环之前以与上述相同的方式在 while
循环中添加所有需要的行,它也会导致 true
。但是,如果粘贴失败而之后没有额外的行,我想中止整个操作。
DataGrid
已将 AutoGenerateColumns
设置为 true
。生成的单元格最初似乎获得 TextBlock
作为内容,后来更改为 TextBox
。问题是,是什么触发了这个变化,我可以手动完成吗?如果我只是将内容更改为 TextBox
以防它是 TextBlock
,我会破坏任何东西吗?
经过一段时间的搜索,我想我找到了问题所在。默认情况下,我已将 属性 DataGrid.CanUserAddRows
设置为 true。在编辑最后一行之后,似乎 DataGrid
在程序化编辑之后添加了一个由 TextBlocks
组成的空行(直到用户在 GUI 中开始编辑)。
在我的粘贴函数开始时将标志设置为 false 并在返回前设置为 true 修复了问题。
我想将 Excel table 中的数据复制粘贴到 WPF DataGrid
中。为此,我有以下函数,它在 KeyDown
事件中被调用:
private void OnDataGridPasteData(object sender, KeyEventArgs e)
{
if ((Keyboard.Modifiers != ModifierKeys.Control) || e.Key != Key.V)
return;
DataGrid dg = (DataGrid)sender;
var pastedData = Clipboard.GetText();
List<string> rowDataCombined = pastedData.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).ToList();
List<string[]> rowData = new List<string[]>();
foreach (var row in rowDataCombined)
{
rowData.Add(row.Split(new string[] { "\t" }, StringSplitOptions.None));
}
int initialRowIdx = Math.Max(dg.Items.IndexOf(dg.SelectedItem), 0);
int initialColIdx = dg.CurrentCell.Column.DisplayIndex;
int maxColIdx = dg.Columns.Count;
int maxRowIdx = initialRowIdx + rowData.Count;
Type sourceType = dg.ItemsSource.GetType().GetGenericArguments()[0];
var sourceList = (IList)dg.ItemsSource;
for (int r = initialRowIdx; r < maxRowIdx; r++)
{
if(r > dg.Items.Count - 1)
{
var newRowObject = Activator.CreateInstance(sourceType);
sourceList.Add(newRowObject);
}
DataGridRow dgRow = GetRowFromDataGrid(dg, r);
if (dgRow == null)
continue;
for (int c = initialColIdx; c < maxColIdx; c++)
{
var presenter = FindVisualChild<DataGridCellsPresenter>(dgRow);
// try to get the cell but it may possibly be virtualized
var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(c);
if (cell == null)
{
// now try to bring into view and retreive the cell
dg.ScrollIntoView(dgRow, dg.Columns[c]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(c);
}
if(cell != null)
{
cell.Focus();
if (!dg.BeginEdit()) //abort pasting if editing fails
{
dg.CancelEdit();
return;
}
if(cell.Content is TextBox tb)
{
tb.Text = rowData[r - initialRowIdx][c - initialColIdx];
}
if(!dg.CommitEdit()) // abort pasting if commit fails (e.g. wrong entry type)
{
dg.CancelEdit();
return;
}
}
}
}
}
注意行 if(cell.Content is TextBox tb)
:
- 对于现有的
DataGridCells
这将是true
- 对于新添加的项目(第
sourceList.Add(newRowObject);
行),这将是错误的。那么内容类型是TextBlock
- 如果我在进入
for
循环之前以与上述相同的方式在while
循环中添加所有需要的行,它也会导致true
。但是,如果粘贴失败而之后没有额外的行,我想中止整个操作。
DataGrid
已将 AutoGenerateColumns
设置为 true
。生成的单元格最初似乎获得 TextBlock
作为内容,后来更改为 TextBox
。问题是,是什么触发了这个变化,我可以手动完成吗?如果我只是将内容更改为 TextBox
以防它是 TextBlock
,我会破坏任何东西吗?
经过一段时间的搜索,我想我找到了问题所在。默认情况下,我已将 属性 DataGrid.CanUserAddRows
设置为 true。在编辑最后一行之后,似乎 DataGrid
在程序化编辑之后添加了一个由 TextBlocks
组成的空行(直到用户在 GUI 中开始编辑)。
在我的粘贴函数开始时将标志设置为 false 并在返回前设置为 true 修复了问题。