Reputation: 5763
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
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