MAUI自定义控件使用GridLength属性触发‘值不能为空’错误
问题解决步骤
1. 修正TypeConverter属性
你写的[TypeConverter(typeof(GridLength))]是错误用法——TypeConverter需要指定转换器类型,而非目标类型。GridLength对应的内置转换器是GridLengthConverter,修正后代码如下:
[TypeConverter(typeof(GridLengthConverter))] public GridLength SpaceBetween { get => (GridLength)GetValue(SpaceBetweenProperty); set => SetValue(SpaceBetweenProperty, value); }
也可以直接去掉这个特性,MAUI默认支持GridLength与字符串的自动转换(比如SpaceBetween="10"会自动转为GridLength(10))。
2. 修复属性变更逻辑
你在CLR属性的setter里调用SetGridColumns是无效的——MAUI绑定系统操作属性时会直接调用SetValue操作BindableProperty,不会走CLR属性的setter,所以断点永远不会触发。正确做法是在BindableProperty创建时指定propertyChanged回调:
public static readonly BindableProperty SpaceBetweenProperty = BindableProperty.Create( nameof(SpaceBetween), typeof(GridLength), typeof(IconButton), new GridLength(0.0), propertyChanged: OnSpaceBetweenChanged); private static void OnSpaceBetweenChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is IconButton button && newValue is GridLength spaceBetween) { button.SetGridColumns(spaceBetween); } } // 简化CLR属性setter,仅负责设置属性值 [TypeConverter(typeof(GridLengthConverter))] public GridLength SpaceBetween { get => (GridLength)GetValue(SpaceBetweenProperty); set => SetValue(SpaceBetweenProperty, value); }
3. 排查“值不能为空”错误
这个错误大概率是两个原因:
IBGrid未初始化就调用了SetGridColumns:请在控件构造函数或生命周期方法(如OnParentSet)中提前初始化IBGrid- TypeConverter错误导致字符串转换失败:修正TypeConverter后即可解决
4. 绑定失效的问题
如果使用SpaceBetween="{Binding SomeValue}"仍不生效,需确认:
- 绑定数据源正确实现了
INotifyPropertyChanged接口 - 绑定路径正确,且数据源属性类型为
GridLength或可转换为GridLength的数值/字符串
修正后的完整关键代码示例:
public class IconButton : View { private Grid IBGrid; public IconButton() { // 初始化IBGrid IBGrid = new Grid(); Content = IBGrid; // 初始化默认列定义 SetGridColumns(new GridLength(0.0)); } public static readonly BindableProperty SpaceBetweenProperty = BindableProperty.Create( nameof(SpaceBetween), typeof(GridLength), typeof(IconButton), new GridLength(0.0), propertyChanged: OnSpaceBetweenChanged); private static void OnSpaceBetweenChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is IconButton button && newValue is GridLength spaceBetween) { button.SetGridColumns(spaceBetween); } } [TypeConverter(typeof(GridLengthConverter))] public GridLength SpaceBetween { get => (GridLength)GetValue(SpaceBetweenProperty); set => SetValue(SpaceBetweenProperty, value); } private void SetGridColumns(GridLength spaceBetween) { IBGrid.ColumnDefinitions = new List<ColumnDefinition> { new ColumnDefinition(GridLength.Star), new ColumnDefinition(GridLength.Auto), new ColumnDefinition(spaceBetween), new ColumnDefinition(GridLength.Auto), new ColumnDefinition(GridLength.Star), }; } }
XAML使用保持不变:
<utils:IconButton Grid.Column="1" Margin="5" IconMargin="10" SpaceBetween="10" LabelText="{Binding MyText}" FontSize="Large" ImageSource="road_sign_warning.svg" ButtonClicked="OnButtonClicked" IconSizeRequest="32" HorizontalOptions="End"/>
内容的提问来源于stack exchange,提问作者GChapX
相关产品推荐
相关产品推荐

