Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data binding doesn't update the property when pressing Enter on a dialog with a default button

My setting is as described below:

  • WPF 4 application
  • MVVM Lite framework
  • An "Add Item" window is shown on top of the main window in dialog mode (using view.ShowDialog();)
  • The dialog has a number of input fields, and the "Save" button that has it IsDefault property set to True
  • "Save" button is handled using a binding to a Command
  • Data binding is defined between the input fields in view's XAML and the corresponding properties in the ViewModel (one way, for the UI to update the ViewModel, with Mode=OneWayToSource)

The problem is that when I press Enter on the keyboard, the value that I provided in the last input field is not pushed to the underlying property of the ViewModel.

I suspect that this has something to do with the fact that the input field hasn't lost the focus before the window is closed (and thus all the bindings are "dissolved"). For comparison, if I click the "Save" button (instead of letting its Click being handled by the window on Enter), the value is updated in the property. Moreover, if I add (horror! horror!) an event handler to the button's Click event, and call button.Focus() in code-behind, everything works!

What can be the remedy?

I obviously don't want to handle any window closing events, and "manually" fetch the missing values... This would violate the whole MVVM concept :-(

Any better suggestions?

Thank you, Alex

like image 513
Alex Avatar asked Sep 09 '11 19:09

Alex


2 Answers

By default, a TextBox only notifies it's source that its value has changed once it loses focus. You can change that in your binding by setting UpdateSourceTrigger=PropertyChanged. This will make the TextBox send an update notification to its source its Text gets changed instead of only when it loses focus.

If you don't want to send an update notification anytime a key is pressed, you can create an AttachedProperty to update the source if the Enter key is pressed.

Here's the AttachedProperty that I use for situations like this:

// When set to True, Enter Key will update Source
#region EnterUpdatesTextSource DependencyProperty

// Property to determine if the Enter key should update the source. Default is False
public static readonly DependencyProperty EnterUpdatesTextSourceProperty =
    DependencyProperty.RegisterAttached("EnterUpdatesTextSource", typeof (bool),
                                        typeof (TextBoxHelper),
                                        new PropertyMetadata(false, EnterUpdatesTextSourcePropertyChanged));

// Get
public static bool GetEnterUpdatesTextSource(DependencyObject obj)
{
    return (bool) obj.GetValue(EnterUpdatesTextSourceProperty);
}

// Set
public static void SetEnterUpdatesTextSource(DependencyObject obj, bool value)
{
    obj.SetValue(EnterUpdatesTextSourceProperty, value);
}

// Changed Event - Attach PreviewKeyDown handler
private static void EnterUpdatesTextSourcePropertyChanged(DependencyObject obj,
                                                          DependencyPropertyChangedEventArgs e)
{
    var sender = obj as UIElement;
    if (obj != null)
    {
        if ((bool) e.NewValue)
        {
            sender.PreviewKeyDown += OnPreviewKeyDownUpdateSourceIfEnter;
        }
        else
        {
            sender.PreviewKeyDown -= OnPreviewKeyDownUpdateSourceIfEnter;
        }
    }
}

// If key being pressed is the Enter key, and EnterUpdatesTextSource is set to true, then update source for Text property
private static void OnPreviewKeyDownUpdateSourceIfEnter(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter)
    {
        if (GetEnterUpdatesTextSource((DependencyObject) sender))
        {
            var obj = sender as UIElement;
            BindingExpression textBinding = BindingOperations.GetBindingExpression(
                obj, TextBox.TextProperty);

            if (textBinding != null)
                textBinding.UpdateSource();
        }
    }
}

#endregion //EnterUpdatesTextSource DependencyProperty
like image 182
Rachel Avatar answered Nov 08 '22 09:11

Rachel


Try this.

{Binding Property,UpdateSourceTrigger=PropertyChanged,Mode=OneWayToSource}

like image 30
Wegged Avatar answered Nov 08 '22 10:11

Wegged