AWG Blogs

Sunday, September 9, 2012

Set ClickMode to Press to Avoid Losing Click Event in DataGrid Column But Note Caveats

For some reason, I was losing the click event for a button in a DataGridTemplateColumn; i.e. the click event (and associated command) would not fire after editing another cell and immediately clicking the (delete) button in the far left column. Setting the ClickMode to Press (rather than the default of Release) appears to fix the issue; i.e. once that is done, the event fires, and I do not have to click Delete twice. There are a couple of steps to take in addition if the DataGrid is bound to a PagedCollectionView that you intend to Refresh() immediately, i.e. within the called Command. These are so as to avoid the error:
An exception of type 'System.InvalidOperationException' occurred in System.Windows.Data but was not handled in user code

Additional information: 'Refresh' is not allowed during an AddNew or EditItem transaction.
1) Add a GotFocus="Button_GotFocus" to the event with method:
        private void Button_GotFocus(object sender, RoutedEventArgs e)
        {
            dataGrid1.CommitEdit(DataGridEditingUnit.Row, true);
        }
Evidently, GotFocus fires before Click here, so it is the place to exit Edit mode.
2) Wrap the pagedCollectionView.Refresh() call in an asynchronous call:

    Deployment.Current.Dispatcher.BeginInvoke(
    () =>
    {
        pagedCollectionView.Refresh();
    });
Evidently, the asynch call delays the refresh long enough so that the row can exit edit mode. These are workarounds that signal a compromise with MVVM and elegance in general, but until I find a better solution, it is what it is.

Use Explicit Binding to Force Update on TextChanged

If you have a TextBox inside a DataTemplate in a DataGrid, and want any TextChanged event to update the binding, set Mode=TwoWay, UpdateSourceTrigger=Explicit on the binding or else you will get an error:
"Operation is not valid due to the current state of the object."

More Notes:

Since this is an Explicit binding, you will need to hook to the event using a behavior such as Prism's UpdateTextBindingOnPropertyChanged. But since that has been made obsolete in Silverlight 5 you will need to get the class itself from the Prism code and add it to your project manually and then attach that like so:
                        <data:DataGridTemplateColumn.CellEditingTemplate>
                            <DataTemplate>
                                <TextBox Height="23" HorizontalAlignment="Left"  
Name="textBox1" VerticalAlignment="Top" Width="120" 
                 
Text="{Binding Invmprop, Mode=TwoWay}" >

                                    <i:Interaction.Behaviors>
                                        <local:MyUpdateTextBindingOnPropertyChanged />
                                    </i:Interaction.Behaviors>
                                </TextBox>
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellEditingTemplate>
Why is it obsolete? Because Silverlight 5 introduced UpdateSourceTrigger=PropertyChanged, which works fine in uncontained textboxes but not when they are in DataGrids (or so I've observed), so for those in DataGrids, I had to perform the above workaround.