在自定义视图上设置可绑定 属性 时,ListDictionaryInternal 出现空引用异常

Null reference exception on a ListDictionaryInternal when setting bindable property on custom view

我刚刚将我的 Xamarin Forms 项目迁移到 .NET Standard 2.0,并且遇到了一些奇怪的行为。在以下情况下,我在 ListDictionaryInternal 上收到空引用异常,没有异常断点,没有堆栈跟踪,也没有其他可用信息。情况是,从我的视图模型中,我在自定义按钮控件上设置了可绑定文本 属性。我已经调试了整个文本设置过程,之后发生了异常。我完全被这个难住了。需要明确的是,此代码在 .NET Standard 2.0 迁移之前有效。提前致谢!

更新:

所以这个异常也开始在 Forms iOS 中发生,但现在我能够在 System.Exception 断点命中时获得堆栈跟踪。此外,这与 .NET Standard 2.0 无关,因为在针对 PCL 4.5 项目时也会发生这种情况,确切地说是配置文件 111。

我可以在 OnSizeAllocated 覆盖方法后面的代码中设置一个断点,然后查看视图是否已接受绑定文本并正确布局。所以问题不在于绑定,而在于视图的布局。

此外,为澄清起见,仅当文本设置为可绑定 属性 时才会发生此异常。如果在 xaml 中设置了文本,则不会发生异常。

ViewModel...

public class SimpleSearchViewModel : BaseViewModel
{
    enum SearchCatagories
    {
        All,
        SubjectId,
        PublicationNumber
    }

    public override void OnStart()
    {
        UpdateTypeButton("ALL");
    }

    private void UpdateTypeButton(string item)
    {
        SearchTypeButtonText = item;
    }

    private string _searchTypeButtonText;
    public string SearchTypeButtonText
    {
        get
        {
            return _searchTypeButtonText;
        }
        private set
        {
            _searchTypeButtonText = value;
            OnPropertyChanged(nameof(SearchTypeButtonText));
        }
    }
}

风景...

<core:BasePage xmlns="http://xamarin.com/schemas/2014/forms" 
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
xmlns:viewmodels="using:App.ViewModels"
xmlns:customcontrols="clr-namespace:App;assembly=App"
xmlns:core="clr-namespace:App.Core;assembly=App.Core"
x:Class="Pages.SimpleSearchPage"
Title="Simple Search">

<ContentPage.BindingContext>
    <viewmodels:SimpleSearchViewModel />
</ContentPage.BindingContext>

<ContentPage.Content>

<StackLayout Padding=" 10, 10, 10, 10" 
             HorizontalOptions="FillAndExpand" 
             VerticalOptions="FillAndExpand" 
             Orientation="Horizontal" > 

            <customcontrols:SVGImageButton x:Name="TypeSelectionButton" 
                            HorizontalOptions="Start" 
                            VerticalOptions="Center"
                            ButtonPressedCommand="{Binding TypeButtonClickedCommand}"
                               SVGImageName="SVGImages.ic_triangle_down.svg"
                            CommandParameter="{x:Reference TypeSelectionButton}"
                            ButtonText="{Binding SearchTypeButtonText}"
                            ButtonBackgroundColor="{Binding ButtonBackgroundColor}"/>

        </StackLayout>
    </ContentPage.Content>
</core:BasePage>

SVGImageButton...

[XamlCompilation(XamlCompilationOptions.Compile)]
public class SVGImageButton : ContentView
{
    private readonly Button _button;
    private readonly SvgCachedImage _svgImage;

    public static BindableProperty ButtonTextProperty =    BindableProperty.Create(nameof(ButtonText), typeof(string),   typeof(SVGImageButton), string.Empty, BindingMode.OneWay, propertyChanged: (bindable, oldValue, newValue) =>
    {
        if (newValue == null) return;
        var control = (SVGImageButton)bindable;
        control.ButtonText = newValue.ToString();
    });

    public string ButtonText
    {
        get
        {
            return _button.Text;
        }
        set
        {
            _button.Text = value; 
        }
    }

    public string SVGImageName { get; set; }

    protected override void OnParentSet()
    {
        base.OnParentSet();

        _button.Text = ButtonText;
        _svgImage.Source = SvgImageSource.FromResource(SVGImageName);
     }

    public SVGImageButton()
    {
        var content = new RelativeLayout();

        _button = new Button { BackgroundColor = Color.Gray, TextColor = Color.Black };
        _svgImage = new SvgCachedImage { IsEnabled = false };

        content.Children.Add(_button,
                             Constraint.RelativeToParent((parent) =>
                             {
                                 return parent.X;
                             }),
                             Constraint.RelativeToParent((parent) =>
                             {
                                 return parent.Y;
                             }),
                             Constraint.RelativeToParent((parent) =>
                             {
                                 return parent.Width;
                             }),
                             Constraint.RelativeToParent((parent) =>
                             {
                                 return parent.Height;
                             }));

        content.Children.Add(_svgImage,
                           Constraint.RelativeToParent((parent) =>
                           {
                               return parent.Width - (parent.Height / 2) - (parent.Height / 4);
                           }),
                           Constraint.RelativeToParent((parent) =>
                           {
                               return parent.Height - (parent.Height /     2) - (parent.Height / 4);
                           }),
                           Constraint.RelativeToParent((parent) =>
                           {
                               return parent.Height / 2;
                           }),
                           Constraint.RelativeToParent((parent) =>
                           {
                               return parent.Height / 2;
                           }));

        Content = content;
        }
    }
}

所以这个问题最终来自于我在 OnMeasure 回调中处理控件大小的方式。正确的问题和答案可见.