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

时间:2017-05-23 16:16:23

标签: wpf datagrid cell visibility edit

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

示例(在框架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; }
        }
    }
}

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

2 个答案:

答案 0 :(得分: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); //<---
}

答案 1 :(得分:0)

如果只有一行折叠的行可以跳过,则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答案的修改进行提交,但由于更改了答案的内容,因此该修改被拒绝。因为我没有足够的代表来添加评论,每{{3} },我将更正作为新答案发布。)