使用隐藏行编辑 DataGrid 中的单元格

Posted

技术标签:

【中文标题】使用隐藏行编辑 DataGrid 中的单元格【英文标题】:Edit cells in DataGrid with hidden rows 【发布时间】:2017-10-23 17:16:45 【问题描述】:

在 WPF 中,我有一个带有一些折叠行的 DataGrid。当我编辑一个单元格然后按 Enter 键时,如果下一行已折叠,则选择不会移动到下一个可见行。相反,我刚刚编辑过的单元格周围是一个虚线矩形,并且键入键盘根本不会导致任何操作。 知道如何使选择跳转到下一个可见行吗? 谢谢

示例(在框架 4.0 下): xml:

<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; 
        
    

通过编辑行并输入回车,您应该会卡在第二行。

【问题讨论】:

请在提问时提供一个最小、完整和可验证的问题示例:***.com/help/mcve 添加了这种行为的例子 【参考方案1】:

知道如何使选择跳转到下一个可见行吗?

此行为已被报告为错误:https://connect.microsoft.com/VisualStudio/feedback/details/526014/keyboard-navigation-doesnt-work-when-the-wpf-datagrid-has-collapsed-or-hidden-rows

您可以通过处理 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); //<---

【讨论】:

这仅适用于我给出的示例,因为它只有一列。在多列数据网格中,这将导致焦点向右移动,而不是在编辑单元格下方。 这就是我要求您提供问题的完整回购的原因之一。显然你没有。 另请注意,此行为已被报告为错误:connect.microsoft.com/VisualStudio/feedback/details/526014/… 虽然也与隐藏行有关,但这是一个不同的错误。 请看我编辑的答案。它应该让您了解如何解决这个问题。【参考方案2】:

如果您只有一个折叠行可以跳过,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,我将更正作为新答案发布。)

【讨论】:

以上是关于使用隐藏行编辑 DataGrid 中的单元格的主要内容,如果未能解决你的问题,请参考以下文章

删除所有 DataGrid 行和单元格边框

更新单个单元格的 UWP DataGrid 样式

无法编辑我的 DataGrid WPF Framework 4.5 的单元格

EasyUI DataGrid 编辑单元格

在WPF DataGrid中按Enter键时将焦点移动到下一个单元格?

EasyUI DataGrid 编辑单元格