绑定与x:Bind:为什么在使用绑定时视图未更新?

时间:2018-12-11 21:59:38

标签: c# mvvm uwp .net-core

我正在开发利用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中插入无效的float值,我想将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帖子的第一条评论,解决此问题的方法是使用<TextBox Text="{x:Bind viewModel.Radius, Mode=TwoWay}"/>而不是上面显示的Binding方法。为什么呢?在这种情况下,Bindingx:Bind有什么区别?

2 个答案:

答案 0 :(得分:2)

绑定到TextBox.Text是一个非常特殊的情况,因为Microsoft决定最常见的情况是,当控件失去焦点时(而不是每个输入文本都发生更改),应该更新绑定。这允许两件事:

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

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

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

现在,在测试场景中,您正在尝试验证并可能更改绑定数据源中的属性值,期望TextBox将显示所需的值,这与{x:Bind}相同,但是不能与{Binding}一起使用。

显然,您发现了{x:Bind}{Binding}实现的行为有所不同的情况。我进行了相同的测试,并完全证实了您的发现。

答案 1 :(得分:1)

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

您可以更改行为UpdateSourceTrigger = PropertyChanged。

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

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

如果此方法不起作用,则可能要防止通过keydown事件输入与数字不同的数字。您可以将其外包给用户控件以重复使用。

希望这会有所帮助。