You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 00:47:32