在具有默认按钮的对话框上按Enter键时,数据绑定不会更新属性

时间:2011-09-09 19:57:22

标签: wpf data-binding mvvm

我的设置如下:

  • WPF 4申请
  • MVVM Lite框架
  • 在对话框模式下,主窗口顶部显示“添加项目”窗口(使用view.ShowDialog();)
  • 该对话框有许多输入字段,并且IsDefault属性设置为True的“保存”按钮
  • 使用绑定到命令
  • 处理“保存”按钮
  • 数据绑定是在视图的XAML中的输入字段和ViewModel中的相应属性之间定义的(单向,UI用于更新ViewModel,模式= OneWayToSource)

问题在于,当我按下键盘上的Enter键时,我在上一个输入字段中提供的值不会被推送到ViewModel的基础属性。

我怀疑这与在窗口关闭之前输入字段没有丢失焦点这一事实有关(因此所有绑定都“解散”)。 为了进行比较,如果我单击“保存”按钮(而不是让Enter上的窗口处理其Click),则在属性中更新值 。 此外,如果我为按钮的Click事件添加(恐怖!恐怖!)事件处理程序,并在代码隐藏中调用button.Focus(),一切正常!

可以采取什么补救措施?

我显然不想处理任何窗口关闭事件,并且“手动”获取缺失值...这将违反整个MVVM概念: - (

有更好的建议吗?

谢谢你, 亚历

4 个答案:

答案 0 :(得分:13)

默认情况下,TextBox只会在失去焦点后通知其来源,其值已更改。您可以通过设置UpdateSourceTrigger=PropertyChanged来更改绑定中的内容。这将使TextBox向其源发送更新通知,其Text将被更改,而不是仅在它失去焦点时。

如果您不想在按下任何键时发送更新通知,则可以创建AttachedProperty以在按下Enter键时更新源。

这是我用于这种情况的AttachedProperty:

// 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

答案 1 :(得分:3)

试试这个。

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

答案 2 :(得分:0)

一个简单的技巧是将焦点移离控件,例如按钮本身。您可以在按钮的Click处理程序中执行此操作,因为它将在绑定命令之前执行:

    public MyView()
    {
        InitializeComponent();

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

如果您不想在视图中使用代码,则还可以在添加到按钮中的行为中执行此操作。

答案 3 :(得分:-3)

这只是一个WPF错误。 (设计或实现,我不知道。)关于焦点丢失的TextBox更新是大多数情况下的预期行为,默认按钮应该在对话框中工作。

对于解决方法,我认为使用TextBox调整是一个错误的方向。更好的解决方案是将焦点强制设置为默认按钮。