【问题标题】:Binding vs x:Bind: Why isn't the view updated when using Binding?Binding vs x:Bind:为什么使用 Binding 时视图没有更新?
【发布时间】:2019-05-12 23:09:00
【问题描述】:

我正在开发一个利用 MVVM 范例的 UWP 应用。我的视图包含一个简单的 TextBox,它的 Text 属性绑定到相应的 ViewModel 属性:

<TextBox Text="{Binding Path=Radius, Mode=TwoWay}"/>

当然,我已将我的 ViewModel 分配给页面的DataContext

public sealed partial class ExamplePage : Page
{
    private ExamplePageVM viewModel;

    public ExamplePage()
    {
        this.InitializeComponent();
        viewModel = new ExamplePageVM();
        DataContext = viewModel;
    }
}

在 ViewModel 中,我执行某种输入验证,即。 e.如果用户在 TextBox 中插入了无效的浮点值,我想将 TextBox 重置为默认值(例如零):

class ExamplePageVM : INotifyPropertyChanged 
{
    public event PropertyChangedEventHandler PropertyChanged;
    private float radius;

    public string Radius
    {
        get => radius.ToString();
        set
        {
            if (radius.ToString() != value)
            {
                if (!float.TryParse(value, out radius)) radius = 0;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Radius)));
            }
        }
    }
}

更改 TextBox 中的值会导致按预期调用 setter。此外,PropertyChanged 事件也会被相应地调用。但是,在 setter 执行完成后,TextBox 仍然包含无效数据,这意味着视图没有正确更新。

根据this帖子的第一条评论,这个问题的解决方案是使用&lt;TextBox Text="{x:Bind viewModel.Radius, Mode=TwoWay}"/&gt;而不是上面显示的Binding方法。为什么呢?在这种情况下,Bindingx:Bind 有什么区别?

【问题讨论】:

    标签: c# mvvm uwp .net-core


    【解决方案1】:

    绑定到TextBox.Text 是一个相当特殊的情况,因为微软做出了一个决定,最常见的情况是当控件失去焦点时应该更新绑定,而不是每次输入文本更改。这允许两件事:

    • 处理较大文本的效率更高
    • 保护正在进行的用户输入不被应用程序更改

    在没有公开可用的 UWP 源代码的情况下,MS 开发人员可能会为您提供更可靠的洞察力,但即使将更改与绑定源进行比较,通过 DependencyObject.RegisterPropertyChangedCallback 直接跟踪 EditBox.TextProperty 也会让您期望实际上,TextBox 中还有一种额外的中间人实现,而不是通常的直接绑定到依赖属性更改,它处理TextProperty 更新如何以及何时影响DataContext 或底层与{Binding}{x:Bind} 绑定的类属性。

    请注意,{x:Bind}{Binding} 是非常不同的机制,尤其是第一个是编译时,第二个是运行时,这意味着它们在内部需要不同的实现,这取决于框架开发人员确保它们表现出相同的行为。

    现在在您的测试场景中,您正在尝试验证并可能更改绑定数据源中的属性值,期望TextBox 将显示您想要的值,它与{x:Bind} 一样,但不是@987654335 @。

    显然,您发现{x:Bind}{Binding} 实现行为不同的场景。我做了同样的测试,完全证实了你的发现。

    【讨论】:

    • 所以基本上,这种奇怪的行为是由于Bindingx:Bind的不同实现而发生的?
    • @IggyBlob 是的,我的直觉是它的内部设计是这样的;例如如果 Binding 设置源属性值 - 它期望 PropertyChanged 事件因此而发生,忽略它并且事后不验证属性值是否匹配 TextBox 显示的值,而 x:Bind 内部更加谨慎。当然,所有这些实现细节都是我的推测,但可以肯定的是 Bindingx:Bind 必须有不同的实现,并且您的测试会显示它们在哪里表现不同。
    【解决方案2】:

    您可能需要自己设置 UpdateTrigger,因为 TextBox 通常会在调用失去焦点时更新源。

    您可以更改行为 UpdateSourceTrigger=PropertyChanged。

    <TextBox Text="{x:Bind AnswerText, UpdateSourceTrigger=PropertyChanged}"/>
    
    <TextBox Text="{Binding AnswerText, UpdateSourceTrigger=PropertyChanged}"/>
    

    如果这不起作用,您可能希望通过 keydown 事件防止输入与数字不同。您可以将其外包给用户控件以供重复使用。

    希望这会有所帮助。

    【讨论】:

    • 感谢您提醒 Binding.UpdateSourceTrigger 这是一个有用的功能,请记住处理 UWP TextBox 和其他文本输入控件,但在这个特定的问题测试场景中它没有帮助。
    • @DK 是对的。 UpdateSourceTrigger=PropertyChanged 在这种特定情况下没有任何区别。
    • @DK 好吧,对不起,我认为有时绑定确实使它变得比它可能/应该更复杂。当我的绑定有时无法正确更新时,我会尝试在 UIThread 上更新它,这可能会有所帮助。当我使用异步方法和 UI 的多次更新时,这可能会发生很多情况,只是时机不好。
    猜你喜欢
    • 2011-01-24
    • 2020-04-05
    • 1970-01-01
    • 2023-04-01
    • 2015-09-17
    • 2014-03-19
    • 2016-09-20
    • 2019-11-29
    • 1970-01-01
    相关资源
    最近更新 更多