WPF绑定:LostFocus触发时点击Save按钮未同步数据的方案探讨
Great question—this is such a common WPF gotcha when sticking with UpdateSourceTrigger=LostFocus for your input bindings! Let’s break down your current approach and explore better alternatives.
Is Your Current Approach Reasonable?
Absolutely. Checking if a focused element is a TextBox and manually calling UpdateSource() before saving is a valid, straightforward fix that directly addresses the core problem: your binding source (the ObservableCollection<MyClass>) doesn’t get updated because the TextBox never triggers LostFocus when the user clicks Save immediately after typing.
You can even refine this approach to be more generic, so it works for any focused input control without hardcoding TextBox checks:
private void SyncFocusedElementBinding() { if (Keyboard.FocusedElement is not FrameworkElement focusedControl) return; // Update text binding (adjust property if using other controls like ComboBox) var textBinding = focusedControl.GetBindingExpression(TextBox.TextProperty); textBinding?.UpdateSource(); }
Call this method right before your save logic, and you’re good to go.
Better, More Maintainable Alternatives
While your current fix works, here are a few cleaner approaches that leverage WPF’s built-in behavior or reusable patterns:
1. Force Focus to the Save Button
Instead of targeting specific controls, just make the Save button take focus before saving. This automatically triggers LostFocus on the active TextBox, letting WPF handle the binding update for you:
private void SaveButton_Click(object sender, RoutedEventArgs e) { // Shift focus to the button first—triggers LostFocus on the TextBox Keyboard.Focus(SaveButton); // Now save your collection (the binding is already synced!) SaveMyCollectionData(); }
This is my go-to solution for simple scenarios—it’s clean, uses WPF’s native focus system, and avoids having to track individual bindings.
2. Reusable Attached Property for Global Binding Updates
If you have multiple input controls (not just TextBoxes) or need this logic across multiple views, create an attached property that automatically updates all bindings when your Save command runs. Here’s a sample implementation:
public static class BindingSyncHelper { public static readonly DependencyProperty UpdateOnSaveCommandProperty = DependencyProperty.RegisterAttached( "UpdateOnSaveCommand", typeof(ICommand), typeof(BindingSyncHelper), new PropertyMetadata(null, OnUpdateCommandChanged)); public static void SetUpdateOnSaveCommand(DependencyObject obj, ICommand value) => obj.SetValue(UpdateOnSaveCommandProperty, value); public static ICommand GetUpdateOnSaveCommand(DependencyObject obj) => (ICommand)obj.GetValue(UpdateOnSaveCommandProperty); private static void OnUpdateCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not Window view || e.NewValue is not ICommand saveCommand) return; // Wrap the existing save command to sync bindings first var originalExecute = saveCommand.Execute; saveCommand.Execute = param => { UpdateAllBindingsInView(view); originalExecute(param); }; } private static void UpdateAllBindingsInView(DependencyObject parent) { foreach (var child in LogicalTreeHelper.GetChildren(parent).OfType<DependencyObject>()) { if (child is FrameworkElement element) { // Update common input bindings—add more as needed element.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); element.GetBindingExpression(CheckBox.IsCheckedProperty)?.UpdateSource(); element.GetBindingExpression(ComboBox.SelectedItemProperty)?.UpdateSource(); } UpdateAllBindingsInView(child); } } }
Then attach it to your window in XAML:
<Window local:BindingSyncHelper.UpdateOnSaveCommand="{Binding SaveCommand}"> <!-- Your UI controls here --> </Window>
Now every time your SaveCommand runs, all bindings in the window sync automatically—no per-view code required.
3. Explicit Binding Updates (MVVM-Friendly)
If you’re using MVVM, you could set UpdateSourceTrigger=Explicit on your bindings, then track binding expressions in your view to update them on save. This is more work, but frameworks like Prism or MvvmLight have utilities to simplify this. It’s best reserved for cases where you need fine-grained control over when bindings sync.
Final Takeaway
Your original approach is totally valid, but forcing focus to the Save button is the simplest and most maintainable fix for most apps. If you need a reusable solution across multiple views, the attached property method is a robust choice.
内容的提问来源于stack exchange,提问作者user3684516

