有没有办法为已编译的绑定获取 UpdateSourceTrigger=PropertyChanged?

Is there a way to get UpdateSourceTrigger=PropertyChanged for compiled bindings?

我正在开发一个 UWP 应用程序,我意识到 TextBox 控件的默认 UpdateSourceTrigger 模式,即 LostFocus,在使用编译绑定。

这意味着每当我想为 TextBox 更新绑定时,我都必须使用所有这些重复的样板文件:

<TextBox
    Text="{x:Bind ViewModel.Title, Mode=TwoWay}"
    TextChanged="TextBox_OnTextChanged"/>
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
    ViewModel.Title = ((TextBox)sender).Text;
}

现在,这还算不错,但是每次使用 TextBox 时都必须记住创建 TextChanged 处理程序,这很烦人且容易出错。

这适用于经典绑定:

<TextBox Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

但是当然,这里会有usinc经典绑定的额外开销(涉及运行时反射等)。

有没有办法获得与 UpdateSourceTrigger=PropertyChanged 相同的行为?我完全可以,比如说,写一个自定义的附加 属性 来设置,只要我可以直接从 XAML 做我需要的一切,不涉及任何代码。

谢谢!

更新: (回应 Nico Zhu - MSFT 的回答)

For my testing, it works well.

它根本不适合我,正如我已经多次说过的,使用 UpdateSourceTriggerx:Bind 只是 不可能 。它不编译,属性 在 XAML 编辑器中显示为红色,只是不存在。如果您说它对您有用,我真的不知道您在哪里尝试。我目前将 17763 作为最低目标,我可以 100% 保证 不会 工作。

Compiled Binding is used with the {x:Bind} syntax as opposed to the {Binding} syntax of Classic Binding.

我很清楚其中的区别,我已经多次提到了这一点,无论是在我的原始问题中(也有代码片段)还是在我的评论中。

It still uses the notifying interfaces (like INotifyPropertyChanged) to watch for changes

正如我所说,我也知道这一点。但是同样,从这个问题来看,这根本不是这里的问题。问题是不是,从视图模型更新到绑定属性,但是来自绑定属性(在本例中为TextBox.Text)视图模型。

{x:Bind} is by default OneTime compared to {Binding} which is OneWay. so you need to declare bind Mode OneWay or TwoWay for {x:Bind}.

抱歉,但此时我不得不说,我开始怀疑您是否真的阅读了我最初的问题。我知道这一点,事实上你可以在 both 我的原始代码片段中看到我已经在我的两个绑定中使用了显式 Mode=TwoWay 属性 .

再一次,这根本不是问题的内容。

重申一下:这里的问题是 TextBox.Text 属性 默认为 LostFocus 触发器,而 UpdateSourceTrigger 属性 是 可用于已编译的绑定。所以我想知道是否有一种方法可以通过编译绑定在 XAML-only 中实现相同的目的,而不必每次都手动创建一个 TextChanged 处理程序(如果没有,如果您计划最终也将 UpdateSourceTrigger 属性 添加到已编译的绑定中)。

旁注:我并不是有意在这里表达不敬,我希望我们现在已经用我的问题解决了现有的误解。

更新 #2: 原来问题是由 ReSharper 插件引起的,该插件将 UpdateSourceTrigger 属性 标记为编译绑定中的错误。 我在这里打开了一个问题:https://youtrack.jetbrains.com/issue/RSRP-474438

请检查 UpdateSourceTrigger 文档。

默认的 UpdateSourceTrigger 值为 Default。和 使用来自使用绑定的依赖项 属性 的默认行为。在 Windows 运行时,这与 PropertyChanged 的值相同。如果您使用 Text="{x:Bind ViewModel.Title, Mode=TwoWay}"标题 将在文本更改时更改。我们不需要修改 TextChanged 甚至处理程序中的视图模式。

前提是我们需要像下面这样实现INotifyPropertyChanged

public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set
        {
            this.nextButtonText = value;
            this.OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

更多细节请参考Data binding in depth文档。

更新

<TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> doesn't compile at all, as I said the UpdateSourceTrigger property isn't available at all when using a compiled binding.

对于我的测试,它运行良好。 Compiled Binding 与 {x:Bind} 语法一起使用,而不是 Classic Binding 的 {Binding} 语法。它仍然使用通知接口(如 INotifyPropertyChanged)来监视更改,但 {x:Bind} 默认是 OneTime,而 {Binding} 是 OneWay。因此您需要为 {x:Bind} 声明绑定 Mode OneWayTwoWay

Xaml

<StackPanel Orientation="Vertical">
    <TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <TextBlock Text="{x:Bind Title, Mode=OneWay}" /> <!--declare bind mode-->
</StackPanel>

代码隐藏

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _title;
public string Title
{
    get
    {
        return _title;
    }
    set
    {
        _title = value;
        OnPropertyChanged();
    }
}