UWP自定义UserControl仅字符串属性生效 枚举、布尔等类型属性赋值失效
问题根源
你遇到的问题本质是两个原因导致的:
- UWP自定义控件需要在XAML中赋值、支持变更响应的属性,必须定义为依赖属性,普通CLR属性的XAML赋值时机晚于控件构造函数执行,且没有内置变更通知能力
- 你根据
ValueUnit计算UnitSymbol的逻辑只执行了一次(大概率写在构造函数中),此时XAML给ValueUnit赋的值还未生效,拿到的永远是枚举的默认值Size
解决步骤
1. 把普通CLR属性改为依赖属性
所有需要在XAML中赋值的控件属性,都需要定义为依赖属性,示例代码如下:
// ValueUnit依赖属性 public Unit ValueUnit { get { return (Unit)GetValue(ValueUnitProperty); } set { SetValue(ValueUnitProperty, value); } } public static readonly DependencyProperty ValueUnitProperty = DependencyProperty.Register("ValueUnit", typeof(Unit), typeof(NumericBox), new PropertyMetadata(Unit.Size, OnValueUnitChanged)); // HasCalc依赖属性 public bool HasCalc { get { return (bool)GetValue(HasCalcProperty); } set { SetValue(HasCalcProperty, value); } } public static readonly DependencyProperty HasCalcProperty = DependencyProperty.Register("HasCalc", typeof(bool), typeof(NumericBox), new PropertyMetadata(false)); // Header依赖属性(推荐改为依赖属性保证绑定兼容性,之前生效是因为字符串类型CLR属性的赋值时机刚好命中读取时机) public string Header { get { return (string)GetValue(HeaderProperty); } set { SetValue(HeaderProperty, value); } } public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(NumericBox), new PropertyMetadata(string.Empty));
2. 在属性变更回调中执行单位符号计算逻辑
上面定义ValueUnit依赖属性时注册了OnValueUnitChanged回调,把你之前的switch逻辑放到这个回调中,只要ValueUnit值发生变化就会自动触发重新计算单位符号:
private static void OnValueUnitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is NumericBox numericBox) { var unit = (Unit)e.NewValue; switch (unit) { case Unit.Currency: numericBox.UnitSymbol = System.Globalization.NumberFormatInfo.CurrentInfo.CurrencySymbol; break; case Unit.Percentage: numericBox.UnitSymbol = "%"; break; case Unit.Size: if (System.Globalization.RegionInfo.CurrentRegion.IsMetric) numericBox.UnitSymbol = "m"; break; case Unit.Weight: if (System.Globalization.RegionInfo.CurrentRegion.IsMetric) numericBox.UnitSymbol = "Kg"; break; } } }
3. 给UnitSymbol添加变更通知(可选,推荐)
如果你使用x:Bind的默认OneTime绑定模式,可能出现值更新后界面不刷新的问题,建议给UnitSymbol实现INotifyPropertyChanged接口,同时把绑定模式改为OneWay:
// 首先让你的UserControl实现INotifyPropertyChanged接口 public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private string _unitSymbol; public string UnitSymbol { get => _unitSymbol; set { _unitSymbol = value; NotifyPropertyChanged(); } }
对应XAML绑定修改为:
<TextBlock Text="{x:Bind UnitSymbol, Mode=OneWay}" VerticalAlignment="Center" Margin="5"/>
修改完成后所有XAML中设置的属性就会正常生效,ValueUnit变更后也会自动更新展示的单位符号。
内容的提问来源于stack exchange,提问作者David Simões
相关产品推荐
相关产品推荐

