使用隐藏行编辑 DataGrid 中的单元格
Edit cells in DataGrid with hidden rows
在 WPF 中,我有一个带有一些折叠行的 DataGrid。当我编辑一个单元格然后按回车键时,如果下一行折叠,则选择不会移动到下一个可见行。取而代之的是,一个虚线矩形围绕着我刚刚编辑的单元格,并且在键盘上键入根本没有任何动作。
知道如何使选择跳转到下一个可见行吗?
谢谢
示例(框架4.0下):
xaml:
<Window x:Class="WpfDataGridEdit.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DataGrid AutoGenerateColumns="False" Name="dataGrid">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Value1}"/>
<DataGridTextColumn Binding="{Binding Path=Value2}"/>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Visibility" Value="{Binding Visibility}" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
</Window>
背后的代码:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfDataGridEdit
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private List<Row> rows = new List<Row>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
this.rows.Add(new Row { Value1 = i.ToString(), Value2 = "x", Visibility = i % 3 == 0 ? Visibility.Collapsed : Visibility.Visible });
this.dataGrid.ItemsSource = this.rows;
}
}
public class Row
{
private string value1;
public string Value1
{
get { return this.value1; }
set { this.value1 = value; }
}
private string value2;
public string Value2
{
get { return this.value2; }
set { this.value2 = value; }
}
private Visibility visibility;
public Visibility Visibility
{
get { return this.visibility; }
set { this.visibility = value; }
}
}
}
通过编辑行并输入回车,您应该会卡在第二行。
Any idea how I can make the selection jump to the next visible row?
您可以通过像这样处理 DataGrid 的 PreviewKeyDown 事件来绕过它:
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
DataGrid dg = sender as DataGrid;
int index = dg.SelectedIndex;
if (index < dg.Items.Count - 1)
{
dg.SelectedIndex++;
DataGridRow nextRow = dg.ItemContainerGenerator.ContainerFromIndex(dg.SelectedIndex) as DataGridRow;
while (nextRow != null && nextRow.Visibility == Visibility.Collapsed)
nextRow = dg.ItemContainerGenerator.ContainerFromIndex(dg.SelectedIndex + 1) as DataGridRow;
if (nextRow != null)
{
dg.SelectedItem = nextRow.DataContext;
dg.CurrentCell = new DataGridCellInfo(nextRow.DataContext, dg.Columns[0]);
}
}
}
}
编辑: 您可能还想通过将事件处理程序连接到 BeginningEdit
事件来保存当前编辑列的索引:
DataGridColumn _lastEditedColumn;
private void dataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
DataGrid dg = sender as DataGrid;
_lastEditedColumn = dg.CurrentCell.Column;
}
..并将 CurrentCell
设置为这个:
if (nextRow != null)
{
dg.SelectedItem = nextRow.DataContext;
dg.CurrentCell = new DataGridCellInfo(nextRow.DataContext, _lastEditedColumn); //<---
}
如果您只有折叠的一行可以跳过,那么 mm8 的回答是完美的。当相邻行折叠时,代码进入无限循环。
获取下一行时,代码应增加 selectedIndex,而不是将 1 加到相同的值。
即将 dg.SelectedIndex + 1
替换为 ++dg.SelectedIndex
像这样:
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
DataGrid dg = sender as DataGrid;
int index = dg.SelectedIndex;
if (index < dg.Items.Count - 1)
{
dg.SelectedIndex++;
DataGridRow nextRow = dg.ItemContainerGenerator.ContainerFromIndex(dg.SelectedIndex) as DataGridRow;
while (nextRow != null && nextRow.Visibility == Visibility.Collapsed)
nextRow = dg.ItemContainerGenerator.ContainerFromIndex(++dg.SelectedIndex) as DataGridRow;
if (nextRow != null)
{
dg.SelectedItem = nextRow.DataContext;
dg.CurrentCell = new DataGridCellInfo(nextRow.DataContext, dg.Columns[0]);
}
}
}
}
注意:通过将 DataGrid 的 SelectedIndex 推进到折叠的行,DataGrid 上的任何 SelectedCellsChanged 或 SelectionChanged 事件都将触发。这可能不适合您的应用程序,具体取决于它在这些事件中的作用。
如果是这种情况,您可能需要考虑使用变量来保存索引,如下所示:
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
DataGrid dg = sender as DataGrid;
int index = dg.SelectedIndex;
int maxIndex = dg.Items.Count - 1;
while (index < maxIndex
&& (dg.ItemContainerGenerator.ContainerFromIndex(++index) as DataGridRow)?.Visibility == Visibility.Collapsed)
{
}
if ((dg.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow)?.Visibility == Visibility.Visible)
{
dg.SelectedIndex = index;
}
}
}
空的 while 循环是故意的,因为索引在条件中提前。 (我不喜欢这种代码风格,但它确实有效)
(背景:我试图将此更正作为对 mm8 答案的编辑提交,但因为它更改了答案的内容,所以编辑被拒绝了。因为我没有足够的代表来添加评论,根据 advice on editing,我将更正作为新答案发布。)
在 WPF 中,我有一个带有一些折叠行的 DataGrid。当我编辑一个单元格然后按回车键时,如果下一行折叠,则选择不会移动到下一个可见行。取而代之的是,一个虚线矩形围绕着我刚刚编辑的单元格,并且在键盘上键入根本没有任何动作。 知道如何使选择跳转到下一个可见行吗? 谢谢
示例(框架4.0下): xaml:
<Window x:Class="WpfDataGridEdit.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DataGrid AutoGenerateColumns="False" Name="dataGrid">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Value1}"/>
<DataGridTextColumn Binding="{Binding Path=Value2}"/>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Visibility" Value="{Binding Visibility}" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
</Window>
背后的代码:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfDataGridEdit
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private List<Row> rows = new List<Row>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
this.rows.Add(new Row { Value1 = i.ToString(), Value2 = "x", Visibility = i % 3 == 0 ? Visibility.Collapsed : Visibility.Visible });
this.dataGrid.ItemsSource = this.rows;
}
}
public class Row
{
private string value1;
public string Value1
{
get { return this.value1; }
set { this.value1 = value; }
}
private string value2;
public string Value2
{
get { return this.value2; }
set { this.value2 = value; }
}
private Visibility visibility;
public Visibility Visibility
{
get { return this.visibility; }
set { this.visibility = value; }
}
}
}
通过编辑行并输入回车,您应该会卡在第二行。
Any idea how I can make the selection jump to the next visible row?
您可以通过像这样处理 DataGrid 的 PreviewKeyDown 事件来绕过它:
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
DataGrid dg = sender as DataGrid;
int index = dg.SelectedIndex;
if (index < dg.Items.Count - 1)
{
dg.SelectedIndex++;
DataGridRow nextRow = dg.ItemContainerGenerator.ContainerFromIndex(dg.SelectedIndex) as DataGridRow;
while (nextRow != null && nextRow.Visibility == Visibility.Collapsed)
nextRow = dg.ItemContainerGenerator.ContainerFromIndex(dg.SelectedIndex + 1) as DataGridRow;
if (nextRow != null)
{
dg.SelectedItem = nextRow.DataContext;
dg.CurrentCell = new DataGridCellInfo(nextRow.DataContext, dg.Columns[0]);
}
}
}
}
编辑: 您可能还想通过将事件处理程序连接到 BeginningEdit
事件来保存当前编辑列的索引:
DataGridColumn _lastEditedColumn;
private void dataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
DataGrid dg = sender as DataGrid;
_lastEditedColumn = dg.CurrentCell.Column;
}
..并将 CurrentCell
设置为这个:
if (nextRow != null)
{
dg.SelectedItem = nextRow.DataContext;
dg.CurrentCell = new DataGridCellInfo(nextRow.DataContext, _lastEditedColumn); //<---
}
如果您只有折叠的一行可以跳过,那么 mm8 的回答是完美的。当相邻行折叠时,代码进入无限循环。
获取下一行时,代码应增加 selectedIndex,而不是将 1 加到相同的值。
即将 dg.SelectedIndex + 1
替换为 ++dg.SelectedIndex
像这样:
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
DataGrid dg = sender as DataGrid;
int index = dg.SelectedIndex;
if (index < dg.Items.Count - 1)
{
dg.SelectedIndex++;
DataGridRow nextRow = dg.ItemContainerGenerator.ContainerFromIndex(dg.SelectedIndex) as DataGridRow;
while (nextRow != null && nextRow.Visibility == Visibility.Collapsed)
nextRow = dg.ItemContainerGenerator.ContainerFromIndex(++dg.SelectedIndex) as DataGridRow;
if (nextRow != null)
{
dg.SelectedItem = nextRow.DataContext;
dg.CurrentCell = new DataGridCellInfo(nextRow.DataContext, dg.Columns[0]);
}
}
}
}
注意:通过将 DataGrid 的 SelectedIndex 推进到折叠的行,DataGrid 上的任何 SelectedCellsChanged 或 SelectionChanged 事件都将触发。这可能不适合您的应用程序,具体取决于它在这些事件中的作用。
如果是这种情况,您可能需要考虑使用变量来保存索引,如下所示:
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
DataGrid dg = sender as DataGrid;
int index = dg.SelectedIndex;
int maxIndex = dg.Items.Count - 1;
while (index < maxIndex
&& (dg.ItemContainerGenerator.ContainerFromIndex(++index) as DataGridRow)?.Visibility == Visibility.Collapsed)
{
}
if ((dg.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow)?.Visibility == Visibility.Visible)
{
dg.SelectedIndex = index;
}
}
}
空的 while 循环是故意的,因为索引在条件中提前。 (我不喜欢这种代码风格,但它确实有效)
(背景:我试图将此更正作为对 mm8 答案的编辑提交,但因为它更改了答案的内容,所以编辑被拒绝了。因为我没有足够的代表来添加评论,根据 advice on editing,我将更正作为新答案发布。)