0
votes

I'm using the MVVM pattern for a simple WPF app. My View has a DataGrid and a Button. My DataGrid has an Attached Property (the purpose of the Attached Property isn't really pertinent to my question).

If I click a cell in the DataGrid and then click the Button, my Attached Property's "OnIsCurrentCellFocusedPropertyChanged" method executes. Here's a snippet from this method:

public static void OnIsCurrentCellFocusedPropertyChanged(DependencyObject source,
                                                         DependencyPropertyChangedEventArgs e)
{
    // This works; I confirmed it's returning the actual DataGrid in my view 
    // and not another "new" instance of DataGrid.
    var datagrid = source as DataGrid;

    if (!(bool)e.NewValue) return;

    // datagrid.CurrentCell is null!
    DataGridColumn cellColumn = datagrid.CurrentCell.Column;
    int colNumber = cellColumn.DisplayIndex;

    // datagrid.SelectedIndex is -1!
    int rowNumber = datagrid.SelectedIndex;

    // more code....
}

XAML snippet showing the AttachedProperty in my DataGrid:

<DataGrid FrozenColumnCount="1" local:CurrentCellFocusedExtension.IsCurrentCellFocused="{Binding IsFocused}" x:Name="companies" ItemsSource="{Binding Companies}"/>

My problem is, I want to get the CurrentCell from my DataGrid, but CurrentCell == null. I suppose this is because when I click the Button, focus shifts to the Button and away from my DataGrid (though the cell is still visibly selected in the view). Also troubling is SelectedIndex returns -1... I can't even get the row index, let alone the selected cell.

Help?

A thought: I could probably subclass DataGrid and add a public "last selected cell" property.

1
I'm guessing (if this is working correctly) that this is firing whenever the DG gets focus or loses focus? If that's true, the grid can get focus without having a cell focused, and can lose focus without a cell being focused. It shouldn't change at all whenever the focused cell changes. You might want to alter the attached property to bind to CurrentCell, which should tell you which cell currently has focus. msdn.microsoft.com/en-us/library/…user1228
The Attached Property is supposed to help reset the cell that has focus after an undo/redo operation changes the DataGrid's ItemsSource. Here's an example: 1) user clicks a cell in row 3. 2) user clicks undo button. 3) ViewModel sets a public bool property to false, resets a collection (used as the DataGrid's ItemsSource), then sets the bool property = true. The AttachedProperty is a bool bound to the VM's bool. It's supposed to refocus the datagrid's selected cell (the cell in row 3, per this example).David Alan Condit
Without code to reset the datagrid's selected row after its ItemsSource is changed, the datagrid's selected row changes to row 1. I want to cancel this behavior, as it's confusing to the user when she clicks the undo button and the datagrid changes the focused row. She has to re-select the row she was on manually (if it wasn't row 1) to see the effect of her undo.David Alan Condit
Seems like the undo functionality should be implemented into the VM. I've done it that way (BeginEdit and AcceptEdit/RevertEdit methods) and by creating my own version of WF4's ModelItem, which wraps POCOs and provides update notification, attached properties, and other UI-centric support like undo/redo tracking. As for this version.... not sure if it would be workable due to the limited surface you have to work with on the DG. Perhaps extend the DG to add undo/redo instead?user1228
Actually, my VM implements the undo/redo commands (with the help of a static "UndoManager" class that is responsible for deep cloning an object that is passed to it and then adding it to its Undo stack (Stack<Object>) or Redo stack). Going back to your first suggestion, you think I should add CurrentCell as a VM property? That might work.David Alan Condit

1 Answers

0
votes

I haven't come up with an Attached Property solution. However, like @Will suggested, I added an int property to my View Model, "SelectedRow." My datagrid binds its SelectedIndex to my vm's SelectedRow using TwoWay binding. Before code fires that changes my datagrid's SelectedIndex, I save it to an int variable, let the code run which changes the datagrid's SelectedIndex, then assign the int variable's value to my vm's SelectedRow property. Because SelectedIndex is bound to SelectedRow via TwoWay binding, the datagrid's SelectedIndex is automatically updated. From the user's perspective, the focused datagrid row never changed.