强制绑定以在触发Command时更新

pok*_*oke 10 wpf binding command mvvm

有没有办法在触发命令之前或之后更新绑定?我有一些文本字段,我可以使用命令编辑和保存,可通过键盘快捷方式访问.由于绑定通常仅在文本字段失去焦点时更新,因此在按下键以保存数据时不会保留最后一次更改.相反,我必须首先跳出文本字段以使其更新然后保存.

有没有办法以优雅的方式强制更新?我正在使用MVVM(但不是任何MVVM框架),所以我想保留命令代码中的UI特定内容.此外,我真的不想在每次更改时更改绑定以更新,只有在焦点丢失时才更新它.

Kai*_*i G 10

如果当前元素是a,您也可以只更新绑定源,而不是更改焦点TextBox.你可以为其他控件做类似的事情,但根据我的经验,我只有这个问题TextBox.

// if the current focused element is textbox then updates the source.
var focusedElement = Keyboard.FocusedElement as FrameworkElement;

if (focusedElement is TextBox)
{
    var expression = focusedElement.GetBindingExpression(TextBox.TextProperty);
    if (expression != null) expression.UpdateSource();
}
Run Code Online (Sandbox Code Playgroud)


use*_*372 5

在您的 上TextBox,您需要UpdateSourceTrigger在文本绑定上设置 ,该绑定定义何时使用文本框值更新源。默认情况下,它LostFocus用于Text属性,这正是正在发生的事情 - 它仅在失去焦点时更新源。您应该设置UpdateSourceTriggerto的值,PropertyChanged它会在每次文本框值更改时更新。

例如

<TextBox ... Text="{Binding Foo, UpdateSourceTrigger=PropertyChanged}"/>
Run Code Online (Sandbox Code Playgroud)

Path 是使用 Binding 命令时的默认属性,所以上面等于 Path=Foo


pok*_*oke 2

我现在已经通过在询问值之前将焦点明确设置到其他元素来解决这个问题。这显然会使当前拥有焦点的元素失去焦点并更新绑定。

为了确定焦点,我根据其他问题的答案编写了一个附加属性。另外,连同我的其他问题,我使这个问题变得有点自动化。

因此,要使用它,我基本上将我的属性附加到一个元素,在本例中是一个选项卡控件:

<TabControl c:Util.ShouldFocus="{Binding ShouldClearFocus}">
Run Code Online (Sandbox Code Playgroud)

在我的视图模型中,我有一个简单的布尔属性ShouldClearFocus,它是引发 a 的标准属性PropertyChangedEvent,因此数据绑定可以工作。然后我简单地设置ShouldClearFocustrue当我想重置焦点时。附加属性会自动设置焦点并再次重置属性值。这样我就可以继续设置ShouldClearFocus,而不必将其设置false在中间。

附加属性是一个标准实现,以此作为其更改处理程序:

public static void ShouldFocusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    if (!(bool)e.NewValue || !(obj is FrameworkElement))
        return;

    FrameworkElement element = (FrameworkElement)obj;
    if (element.Focusable)
        element.Focus();

    // reset value
    BindingExpression bindingExpression = BindingOperations.GetBindingExpression(obj, ShouldFocusProperty);
    if (bindingExpression != null)
    {
        PropertyInfo property = bindingExpression.DataItem.GetType().GetProperty(bindingExpression.ParentBinding.Path.Path);
        if (property != null)
            property.SetValue(bindingExpression.DataItem, false, null);
    }
    else
        SetShouldFocus(obj, false);
}
Run Code Online (Sandbox Code Playgroud)