开发者

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


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


Try this.

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


A simple trick is to move the focus away from the control e.g. to the button itself. You can do this in the Click handler of the button, as it will be executed before the bound command:

    public MyView()
    {
        InitializeComponent();

        _button.Click += delegate
        {
            _button.Focus();
        };
    }

If you don't like code behind in your view, you can also do this in a behavior you add to your button.


It is simply a WPF bug. (Design or implementation, I don't know.) TextBox update on focus lost is the expected behavior in most of the cases and also default button should work in dialogs.

For workaround, I think it is a wrong direction to temper with the the TextBox. Better solution is to force focus to the default button.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜