【问题标题】:Is there a way to get UpdateSourceTrigger=PropertyChanged for compiled bindings?有没有办法为已编译的绑定获取 UpdateSourceTrigger=PropertyChanged?
【发布时间】:2019-09-10 21:35:28
【问题描述】:

我正在开发一个 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 的回答)

对于我的测试,它运行良好。

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

编译绑定与 {x:Bind} 语法一起使用,而不是经典绑定的 {Binding} 语法。

我很清楚其中的区别,我已经多次提到这一点,无论是在我的原始问题中(也包含代码 sn-ps)以及在我的 cmets 中。

它仍然使用通知接口(如 INotifyPropertyChanged)来监视更改

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

{x:Bind} 默认是 OneTime,而 {Binding} 是 OneWay。所以你需要为 {x:Bind} 声明绑定模式 OneWay 或 TwoWay。

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

再一次,这不是问题的意义所在。

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

旁注:我不是故意在这里听起来不尊重,我希望我们现在已经解决了我的问题存在的误解。

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

【问题讨论】:

    标签: c# xaml uwp windows-10-universal


    【解决方案1】:

    请查看UpdateSourceTrigger 文档。

    默认的 UpdateSourceTrigger 值为Default。和 使用使用绑定的依赖属性的默认行为。在 Windows 运行时,这与 PropertyChanged 的值相同。如果你使用了Text="{x:Bind ViewModel.Title, Mode=TwoWay}"Title 会随着文本的变化而变化。在TextChanged甚至handler中我们不需要修改viewmode。

    前提是我们需要像下面这样实现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文档。

    更新

    &lt;TextBox Text="{x:Bind Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /&gt; 根本无法编译,正如我所说,UpdateSourceTrigger 属性在使用已编译绑定时根本不可用。

    对于我的测试,它运行良好。编译绑定与 {x:Bind} 语法一起使用,而不是经典绑定的 {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();
        }
    }
    

    【讨论】:

    • 您好,感谢您的帮助,但这并不能真正回答我的问题。我知道默认的UpdateSourceTrigger 值是Default,在 99% 的情况下它的行为类似于PropertyChanged。我是说,具体来说,TextBox 控件的Text 属性默认使用LostFocus 触发器,并且在使用编译绑定时,无法直接从绑定表达式更改该模式在 XAML 中(与经典绑定不同,如我的问题所示)。有什么方法可以直接从 XAML 执行此操作,而无需 TextChanged 处理程序?
    • @Sergio0694,好的,我会检查的。
    • 谢谢,非常感谢! ?
    • @Sergio0694 不太确定我们是否完全理解了这个问题。但是我和我的大学 Nico 一起工作过,下面的代码实际上在我们这边工作: 你能先运行下面的sample 吗?如果它不起作用,您介意告诉我们您的详细操作系统版本吗?例如,当我输入 winver 时,我会得到 17763.437
    • 嘿@BarryWang-MSFT 和 Nico Zhu - 非常感谢您的帮助!我已经测试了您的复制项目,经过更多调查后,我终于弄清楚了导致问题的原因(我认为这里也存在误解),是 ReSharper 将UpdateSourceTrigger 属性标记为我的错误。禁用它可以解决问题。我已经在 ReSharper 问题跟踪器 (youtrack.jetbrains.com/issue/RSRP-474438) 上打开了一个问题,希望他们能尽快修复它!谢谢大家的帮助,祝你有美好的一天! ?
    猜你喜欢
    • 2011-04-15
    • 2013-10-22
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多