James Cronen
James Cronen

Reputation: 5763

Manipulate order of WPF TextBox LostFocus event and binding

I have a WPF Window that represents a data editor. The DataContext of the Window is of an observable object (which implements INotifyPropertyChanged).

Each of the observable object's properties is bound to an appropriate widget in the Window (TextBox for numeric types, CheckBox for bool, etc.).

I don't want to have "OK" and "Cancel" buttons to persist changed properties; I'd like the underlying data to be persisted to the observable object when the widget loses focus.

To do this, I've handled the PreviewLostKeyboardFocus and LostFocus events for the widget. My undo framework requires a copy of the observable object representing the current state, and a copy of the new state. The PreviewLostKeyboardFocus event makes a copy of the object, and the LostFocus event actually performs the save to the database.

But my problem is this: the Binding on the field doesn't actually update the underlying observable object until after the LostFocus event is run. The net effect is that changing the text in a TextBox from "A" to "B" would persist the data in the field as "A". Changing it from "A" to "B" to "C" would persist "B".

I've put breakpoints in the event handlers and in the setter of the underlying object. Sure enough, PreviewLostKeyboardFocus runs first, then LostFocus, then finally the observable object's setter.

I want to make this as generic as possible, so while I could tell the observable object to update its own property using the KeyboardFocusChangedEventArgs, I'd need separate event handlers for each field, and there could be quite a few.

Is there any way to get the Binding to run between the PreviewLostKeyboardFocus and LostFocus events?

XAML:

<TextBox Text="{Binding ObjectProperty, StringFormat='{}{0:F5}'}" LostFocus="PersistentTextBox_LostFocus" PreviewLostKeyboardFocus="PersistentTextBox_PreviewLostKeyboardFocus" />

Event-handlers in code behind:

private void PersistentTextBox_LostFocus(object sender, RoutedEventArgs e) {
    this.ObservableObject.PersistChanges(this.tempObservableObject);
}

private void PersistentTextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
    this.tempObservableObject = this.ObservableObject;
}

ObservableObject class (setter):

public class ObservableObject : INotifyPropertyChanged {
    ...
    public Single ObjectProperty {
        get {
            return this._objectProperty;
        }
        set {
            this._objectProperty = value;
            RaisePropertyChanged("ObjectProperty");
        }
    }
}

Thanks!

Upvotes: 5

Views: 7249

Answers (1)

sa_ddam213
sa_ddam213

Reputation: 43596

If I understand your question correctly, This may be due to the fact that by default the TextBox updates the Source when focus is lost.

One way to solve this could be to set the TextBox UpdateSourceTrigger to PropertyChanged

<TextBox Text="{Binding ObjectProperty, UpdateSourceTrigger=PropertyChanged, StringFormat='{}{0:F5}'}" 

This will allow the underlying observable object to be updated as soon as a change is made in the TextBox, Then you can persist the changes in the widgets lost focus events

Or you could set the UpdateSourceTrigger to Explicit and update the Source in the LostFocus handler.

 <TextBox Text="{Binding ObjectProperty, UpdateSourceTrigger=Explicit, StringFormat='{}{0:F5}'}" 

    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
    {
       (sender as TextBox).GetBindingExpression(TextBox.TextProperty).UpdateSource();
    }

Upvotes: 7

Related Questions