将选定的 WPF DataGridCell 设置为聚焦且可编辑事件

问题描述 投票:0回答:2

Woot,第一篇 Stack Overflow 帖子!我被要求开发一个桌面应用程序来改进我公司的库存流程。我在学校接触过 WPF,我想我应该从那里开始。经过一番研究,我了解了MVVM,进行了设计,然后继续前进。最后,我陷入困境,寻求一些帮助,并进行健全性检查,看看我是否走在正确的道路上。

我有绑定到可观察集合的单列 DataGrid。应用程序的用户使用扫描枪输入值。我在“Cell”模型对象中捕获的一个潜在值是“MoveNextColumn”值。这会在我的模型中引发一个在视图模型中处理的自定义事件。该处理程序应该模拟该列中所有剩余行的空白条目,将焦点设置在最后一行,并在继续之前等待输入。这就是我到目前为止所拥有的:

private void dummyCell_MoveToNextColumn(object sender, RoutedEventArgs e) {
        e.Handled = true;

        // Cell is the model object containing the parsing rules and raising events
        var lSender = sender as Cell;
        var gridItems = ViewGridReference.Items;
        var lastItem = gridItems[gridItems.Count - 1];

        if (lSender == lastItem) {
            // We are at the bottom of the column
            // Move the program on to the next column
            CurrentColumn++;
            OnPropertyChanged("ItemPositions");
        } else {
            // Simulate "empty position" input for this cell and all cells down the column
            // Cells are validating themselves as the simulation progresses
            foreach (Cell item in ViewGridReference.Items) {
                item.ActualItemCode = string.Empty;
            }

            // ViewGridReference is a reference to my DataGrid set from the view
            ViewGridReference.Focus();

            ViewGridReference.SelectedIndex = gridItems.Count - 1;
            ViewGridReference.CurrentCell = new DataGridCellInfo(lastItem, ViewGridReference.Columns[0]);
            ((DataGridCell)ViewGridReference.SelectedItem).Focus();             
        }                                   
    }

所有这些似乎都按预期工作:所有行都接收空白输入并经过验证(我在视图绑定到的单元格中使用颜色属性来表示条目的有效性)。

不幸的是,尽管焦点位于所需的最后一行,但它不可编辑,并且用户无法提交另一个“MoveNextColumn”值来继续移动程序。这里的目标是尽量减少任何键盘交互。一切都应该用扫描枪和条形码来完成。

关于如何在执行此代码后使所选单元格可编辑有什么想法吗? 任何“嘿,你的设计很糟糕”的反馈也很酷。这对我来说是新的,我愿意接受建设性的批评。

c# wpf datagrid focus
2个回答
0
投票

我在这方面取得了一些进展。在上面的代码中,整个网格处于不可编辑状态。现在,焦点集中在我的列中的最后一个单元格上,并允许我使用扫描枪提交输入。

这似乎有效,但我仍然希望得到一些关于是否有更好的方法的反馈。

private void dummyCell_MoveToNextColumn(object sender, RoutedEventArgs e) {
        e.Handled = true;

        // Cell is the model object containing the parsing rules and raising events
        var lSender = sender as Cell;
        var gridItems = ViewGridReference.Items;
        var lastItem = gridItems[gridItems.Count - 1];

        if (lSender == lastItem) {
            // We are at the bottom of the column
            // Move the program on to the next column
            CurrentColumn++;
            OnPropertyChanged("ItemPositions");
        } else {
            // Simulate "empty position" input for this cell and all cells down the column
            // Cells are validating themselves as the simulation progresses

            foreach (Cell item in ViewGridReference.Items) {
                item.ActualItemCode = string.Empty;
            }

            ViewGridReference.SelectedIndex = gridItems.Count - 1;
            ViewGridReference.CurrentCell = new DataGridCellInfo(lastItem, ViewGridReference.Columns[0]);

            (ViewGridReference.ItemsSource as ListCollectionView).EditItem(ViewGridReference.SelectedItem);
            ((DataGridCell)ViewGridReference.SelectedItem).Focus();                                         
        }                                   
    }

更新于2010年12月2日

嘿,有一个重要的更新。首先要注意的是,在我的场景中,文本输入是使用扫描枪完成的,因此每次扣动扳机时都会按下“Enter”键。它会一次性击落每个字符,然后按 Enter 键。

WPF 看到此输入并希望将焦点设置到接收 Enter 键输入的单元格正下方的 DataGridCell。上面的代码将焦点设置到最后一个单元格,但运行此代码后,Enter 键事件仍会触发并由 DataGrid 处理。效果是焦点重置回后续单元格,而不是像我想要的那样最后一个单元格。

因此,我需要弄清楚如何在该扫描中使用 Enter 键,或者需要破坏 WPF 处理 Enter 键的方式。最后一行实际上抛出了一个异常。我们正在尝试使用模型类 (Class.cs) 作为 DataGridCell,但没有任何东西可以处理该转换。因此,Focus() 方法尝试对 null 对象进行操作,并且我们得到 NullReferenceException。这真的让我很困惑,因为 Visual Studio 2010 有时会中断来提醒我这一点,但有时却不会。但是,如果我在 Visual Studio 之外运行可执行文件,它就可以正常工作。这是因为未处理的非致命异常会被忽略,并且 Enter 键行为无法正常运行。

所以它有效,但是以一种非常恶心的方式。我要么需要弄清楚如何一次性处理 Enter 键并覆盖默认的 WPF 处理程序,要么就保持原样并做鬼脸。


0
投票

所以我在同样的问题上挣扎了很长时间,并且我能够从类似的帖子中获得一些解决方案在wpf datagrid中单击编辑

最终我的代码看起来像这样:

private void btnAddRecordClick (object sender, RoutedEventArgs e)
{
    DataGrid grid = myDataGrid;
    DataGridCellInfo cellInfo = new DataGridCellInfo(grid.Items[grid.Items.Count -1], grid.Column[0]);
    grid.CurrentCell = cellInfo;
    grid.SelectedCells.Clear();
    grid.SelectedCells.Add(cellInfo);

    DataGridCell cell = (DataGridCell)cellInfo.Column.GetCellContent(cellInfo.Item).Parent;
    TextBox textBox = GetChildByType<TextBox>(cell.Content as ContentPresenter);

    if (textBox !- null)
        textBox.Focus();
}

private T GetChildByType<T> (DependencyObject prop) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(prop); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild((prop), i) as DependencyObject;

        if (child == null)
            continue;

        T castProp = child as T;
        if (castProp != null)
            return castProp;

        castProp = GetChildByType<t>(child);
        if (castProp != null)
            return castProp;
    }

    return null;
}

我当然希望这对那里的人有帮助。当然,这个解决方案让我有些惊愕。

© www.soinside.com 2019 - 2024. All rights reserved.