使用x:Reference的XAML绑定失效,但代码绑定正常,原因何在?
问题描述
我有一个ContentView,它暴露了一个可绑定的布尔属性:
public static readonly BindableProperty ShowCurrentIntervalInfoProperty = BindableProperty.Create(nameof(ShowCurrentIntervalInfo), typeof(bool), typeof(WorkoutTimerBottomView), defaultBindingMode: BindingMode.TwoWay); public bool ShowCurrentIntervalInfo { get => (bool)GetValue(ShowCurrentIntervalInfoProperty); set => SetValue(ShowCurrentIntervalInfoProperty, value); }
在该ContentView的XAML中,我设置了两个标签和一个按钮来演示问题:
<Label x:Name="label1" Text="{Binding Source={x:Reference workoutTimerBottomView}, Path=ShowCurrentIntervalInfo}"/> <Label x:Name= "label2"/> <Button Clicked="Button_Clicked"/>
对应的后台代码如下:
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) { if (propertyName == nameof(ShowCurrentIntervalInfo)) { label2.Text = ShowCurrentIntervalInfo.ToString(); } } private void Button_Clicked(object sender, EventArgs e) { ShowCurrentIntervalInfo = !ShowCurrentIntervalInfo; }
点击按钮时,label2的文本会通过OnPropertyChanged中的代码在True和False间切换,但label1的文本始终保持为False。
注:ContentView实例名称与x:Reference一致,已在ContentView标签中设置:
x:Name="workoutTimerBottomView"
我不确定这是已知问题还是我对绑定存在误解?
问题原因与解决方案
问题出在绑定的源引用时机:XAML解析时,workoutTimerBottomView实例尚未完全初始化,绑定会取ShowCurrentIntervalInfo的默认值False;后续属性变更时,该绑定不会自动更新——因为直接绑定到控件实例的CLR属性,没有关联可绑定属性的变更通知机制。
以下两种方案可解决问题:
方案1:使用相对绑定关联可绑定属性
修改label1的绑定,用RelativeSource Self直接引用当前ContentView实例,确保绑定监听可绑定属性的变更通知:
<Label x:Name="label1" Text="{Binding ShowCurrentIntervalInfo, Source={RelativeSource Self}}"/>
方案2:设置控件自身为BindingContext
在ContentView的构造函数中设置BindingContext = this;:
public WorkoutTimerBottomView() { InitializeComponent(); BindingContext = this; }
然后简化XAML中的绑定:
<Label x:Name="label1" Text="{Binding ShowCurrentIntervalInfo}"/>
补充说明
label2能正常更新是因为你在OnPropertyChanged中手动修改了文本;而label1的绑定未收到变更通知,是因为CLR属性本身不会触发绑定系统的更新机制——只有可绑定属性的SetValue方法才会触发PropertyChanged事件,绑定必须关联到这个机制才能同步更新。
内容的提问来源于stack exchange,提问作者Toto
相关产品推荐
相关产品推荐

