简体   繁体   中英

Set selected WPF DataGridCell to focused and editable upon event

Woot, first Stack Overflow post! I've been asked to work on a desktop application to improve an inventory process for my company. I dabbled with WPF in school and I figured I'd start there. After researching some, I learned about MVVM, put a design together, and forged ahead. Finally, I'm stuck and looking for some help and also a sanity check to see if I'm on the right path.

I have single-column DataGrid bound to an observable collection. Users of the application use a scan gun to enter values in. One potential value that I catch in my "Cell" model object is a "MoveNextColumn" value. This raises a custom event in my model that is handled in the View Model. The handler is supposed to simulate blank entries for all remaining rows in that column, set focus on the last row, and wait for input before moving on. So here is what I have so far:

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();             
        }                                   
    }

All of this seems to be working as expected: all rows receive blank input and are validated (I use color properties in the cell to which the view binds to signify the validity of the entry).

Unfortunately, though the focus is on the last row as desired, it is not editable and the user cannot submit another "MoveNextColumn" value which would move the program on. The goal here is to minimize any keyboard interaction. Everything should be done with scan guns and barcodes.

Any ideas on how to make the selected cell editable after this code executes? Any "hey, your design sucks" feedback would be cool too. This is new to me and I'm open to constructive criticism.

I have made some progress with this. The entire grid was left at an uneditable state in the code above. This now leaves focus on the last cell in my column and allows me to submit input with the scan gun.

This seems to work, but I'd still appreciate some feedback on whether there is a better way.

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();                                         
        }                                   
    }

Updated 12/2/2010

Hey, there is an important update to this. The first thing to note is that text entry is being done with a scan gun in my scenario, so 'Enter' keys are sent down with each pull of the trigger. It shoots down each character followed by the Enter key all at once.

WPF sees this enter and wants to set the focus to the DataGridCell directly beneath the cell in which the Enter key input was received. The code above sets the focus to the last cell, but then the Enter key event still fires and is handled by DataGrid after this code is run. The effect is that the focus is reset back to the subsequent cell, not the last cell like I want.

So I need to either figure out how to eat the Enter key for just that scan, or I need to break how WPF handles Enter keys. The last line up there actually throws an exception. We are trying to use a Model class (Class.cs) as a DataGridCell, and there is nothing to handle that cast. Because of that, the Focus() method tries to operate on a null object and we get a NullReferenceException. This was really confusing me because Visual Studio 2010 would sometimes break to alert me about this, but sometimes it wouldn't. However, if I run the executable outside of Visual Studio, it works just fine. That's because unhandled, non-fatal exceptions are ignored and the Enter key behavior fails to operate as normal.

So it works, but in a pretty gross way. I either need to figure out how to do one-time handling of the Enter key and override the default WPF handler, or just leave it like it is and grimace.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM