当我尝试将全局样式应用于Xamarin Forms中的自定义ContentView时,NullReferenceException

我为我的项目创建了控件层次结构:abstract BaseSettingsElement和inherited EntrySettingsElementPickerSettingsElementSwitchSettingsElement等。基类提供了更改文本,颜色,标题/子标题字体的属性。 财产申报示例:

 public static readonly BindableProperty HeadTextColorProperty = BindableProperty.Create("HeadTextColor", typeof(Color), typeof(BaseSettingsElement), Color.FromHex("#ffffff"), propertyChanged: (bindable, oldValue, newValue) => { (bindable as BaseSettingsElement).headText.TextColor = (Color)newValue; }); //... public Color HeadTextColor { get { return (Color)GetValue(HeadTextColorProperty); } set { SetValue(HeadTextColorProperty, value); } } 

当我在xaml中创建这个控件并对它们应用一些属性时没有问题:

   

但是当我尝试将app.xaml中的全局样式应用于我的某些控件时,我在这里有一个NullRefferenceException

 public static readonly BindableProperty HeadTextColorProperty = BindableProperty.Create("HeadTextColor", typeof(Color), typeof(BaseSettingsElement), Color.FromHex("#ffffff"), propertyChanged: (bindable, oldValue, newValue) => { (bindable as BaseSettingsElement).headText.TextColor = (Color)newValue; //Here is a NullReferenceException: bindable object is not null but the field 'headText' is null... }); 

以防万一基本控件的xaml:

                 

快速浏览一下编译器生成的文件(.xaml.g.cs) – 您会注意到这些私有字段是在InitializeComponent方法中分配的:

 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")] private void InitializeComponent() { global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(BaseSettingsElement)); headText = global::Xamarin.Forms.NameScopeExtensions.FindByName(this, "headText"); } 

因此,这似乎是由于调用InitializeComponentPropertyChangedHandler的顺序引起的问题。

在第一种情况下,当显式设置属性时,这是调用方法的顺序。

 InitializeComponent -Start InitializeComponent -End HeadTextColor -PropertyChanged 

而在第二种情况下,在使用全局样式设置属性时,顺序为:

 HeadTextColor -PropertyChanged InitializeComponent -Start InitializeComponent -End 

看起来该属性设置在基类构造函数中的某处。 所以NullReferenceException是预期的。

有两种方法可以解决它。

解决方案-1(推荐)

而不是使用属性更改的处理程序,使用Binding在内部子控件上设置属性,父节点为Source 。 例如:

      

解决方案-2

或者,在InitializeComponent之后设置内部控件的属性。

 public MyView() { Debug.WriteLine("InitializeComponent -Start"); InitializeComponent(); Debug.WriteLine("InitializeComponent -End"); //InitializeControl(); this.headText.TextColor = HeadTextColor; } 

注意:在第二个解决方案中,您仍然需要属性更改的处理程序。 否则,在XAML中显式设置属性不会将更改传播到内部控件。 我想这是一个空检查。