Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converters are being called on every keystroke rather than at the end of user input

I'm having a problem with data entry since switching to .NET 4.0. In my Xceed 3.7 grid, the user used to be able to type a value into a cell, and when they clicked away or hit enter, the bound converter's ConvertBack method would be called, parsing the user input value and storing in the desired format.

Now all of the sudden, this is happening every keystroke - which is causing a huge problem, because if the user erases a number and starts typing another one, (lets say -100), as soon as they type the negative sign, the convertback fires and throws an exception because "-" is not a parsable string, and the value is reverted.

I think the problem is pretty clear, so now I'll paste in some code.

Columns for user input appear as follows:

<xcdg:DataGridControl x:Name="AggCatGrid01"
      ItemsSource="{Binding Source={StaticResource myDataSource}}" >
<xcdg:DataGridControl.Columns>
      ...
      <xcdg:Column VisiblePosition="0" FieldName="SomeValue" Title="Some Value"
                   CellEditor="{StaticResource PercentageEditor}"
                   CellContentTemplate="{StaticResource EditablePercent2CellContentTemplate}" />

Datagrids all share the same style:

<Style x:Key="{x:Type xcdg:DataGridControl}" TargetType="{x:Type xcdg:DataGridControl}">
    <Setter Property="UpdateSourceTrigger" Value="CellEndingEdit"/>
    <Setter Property="AutoCreateColumns" Value="False"/>
    <Setter Property="EditTriggers" Value="BeginEditCommand, CellIsCurrent, ActivationGesture"/>
    <Setter Property="CellEditorDisplayConditions" Value="CellIsCurrent"/>
    <Setter Property="NavigationBehavior" Value="CellOnly"/>

Notice that UpdateSourceTrigger is set to CellEndingEdit. I would have thought that this right here would be responsible for when the converters get called and the bound value is updated. Whatever controls that changed just by switching .NET4 though.

Here's the data template for the column you saw used above:

<!-- Styles used when editable cells are being edited. -->
<xcdg:CellEditor x:Key="PercentageEditor">
    <xcdg:CellEditor.EditTemplate>
        <DataTemplate>
            <xcdg:AutoSelectTextBox Style="{StaticResource DefaultAutoSelectTextBox}"
                                    Text="{xcdg:CellEditorBinding Converter={StaticResource EditablePercentageConverter}}" />
        </DataTemplate>
    </xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>

I think the converter code itself is irrelevant, so I'll leave it out unless it's requested. The problem is that it's getting called every keystroke.

If you can shed any light on this, I'd be ecstatic. I mean, I might have to roll back all my .NET 4.0 enhancements, or delay my next release by upwards of a month rewriting all my datagrids to no longer use xceed if there isn't a solution to this. Thanks guys.


Update #1

I actually came up with a moderately clever workaround (in my modest opinion) where I introduce a dummy textblock to hold the CellEditorBinding xceed forces us to use in the datatemplate. I then changed my input control to bind to the textblock's text property rather than the CellEditorBinding directly, which allowed me to specify my own binding mode. Here I was able to set the mode to 'lostFocus' and the major problem was solved! Converter is no longer being called on every keystroke, but only when the user leaves the cell or hits enter.

<xcdg:CellEditor x:Key="PercentageEditor">
    <xcdg:CellEditor.EditTemplate>
        <DataTemplate>
            <Grid>                        
                <TextBlock x:Name="bind_source" Text="{xcdg:CellEditorBinding}" Visibility="Collapsed"/>
                <xcdg:AutoSelectTextBox Style="{StaticResource DefaultAutoSelectTextBox}"
                    Text="{Binding ElementName=bind_source, Path=Text, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditablePercentageConverter}}" />
            </Grid>
        </DataTemplate>
    </xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>

As you can imagine though, this layer of indirection has cause a few other minor issues, such as breaking validation. Oddly enough, now when the user types invalid data, the converter throws an exception which xceed catches and uses to turn on the cell's error template, but correcting the error and hitting enter no longer works. The user's only option is to hit the ESC key, causing the cell value to revert and lose focus, before they can correct their entry.

User must hit ESC in this situation to continue editing cells. Simply clicking away or changing the value back to something valid doesn’t work.

I'm still hoping for a more elegant solution that will fix this.


Update #2

I found a developer on Xceed support forums which presented the same issue as me in this post: http://silverlightdatagrid.com/CS/forums/permalink/31548/31516/ShowThread.aspx#31516.

Many users seem totally confused by your examples (which are largely out of date for .Net 4.0) and only target your own controls using the xcdg:CellEditorBinding which only seems to support PropertyChanged validation.

Unfortunately no solution was ever offered. He did present a strategy for changing the update source trigger more elegantly which I was able to adopt, but I still have the problem of the validation error freezing the cell until the user hits ESC.

<xcdg:AutoSelectTextBox Style="{StaticResource DefaultAutoSelectTextBox}"
     Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=xcdg:DataCell}, 
                    Path=Content, UpdateSourceTrigger=LostFocus, 
                    Converter={StaticResource EditablePercentageConverter}}" />

Update #3

I have confirmed that by updating to Xceed DataGrid version 4.3 (on trial), the problem went away all on its own, as in that version, Xceed updated its xcdg:CellEditorBinding UpdateSourceTrigger incompatibility with .Net4.0. Since, however, a license for Xceed only includes 6 months of bug fix updates before you have to pay for a whole new license (ridiculous), and I don't see any company authorizing an outrageous $1200 single developer license fee to use the latest Xceed dll just for this one minor bug, I'm still going to strive to find a complete workaround in the 3.7 version of Xceed. I'll present this 'solution' for the developers that have access to money to burn.

As it turns out, upgrading to 4.3 didn't solve the problem. It only appeared to because I'd forgotten to back out my previous change. Even in the latest version, Xceed still hasn't exposed the UpdateSourceTrigger property on on CellEditorBinding.

like image 669
Alain Avatar asked Jan 25 '12 14:01

Alain


1 Answers

The solution is:

<xcdg:AutoSelectTextBox Style="{StaticResource DefaultAutoSelectTextBox}"
     Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=xcdg:DataCell}, 
                    Path=Content, UpdateSourceTrigger=LostFocus, 
                    Converter={StaticResource EditablePercentageConverter}}" />

There's really no other way to do it. If you aren't using the latest version of Xceed, this will also lead to validation errors, but in the latest version, using this new binding path works perfectly. I still think it's a hack, and hopefully xceed will realize it needs to expose a few more properties on its CellEditorBinding.

like image 174
Alain Avatar answered Oct 12 '22 05:10

Alain