【问题标题】:NullReferenceException when referencing element if I execute InitializeComponent on parent class [closed]如果我在父类上执行 InitializeComponent 引用元素时出现 NullReferenceException [关闭]
【发布时间】:2019-08-25 20:09:25
【问题描述】:

编辑:它被错误地标记为重复,因为它不是关于识别 NullReferenceException 甚至是理解它是什么......它是关于弄清楚为什么扩展原生 InitializeComponent() 调用会使无法引用上层类的 XAML 元素。为什么那个特定的超级调用会导致 NullReference。希望有能力看到差异的人会理解。谢谢。


我有一个MyPage->BasePage->ContentPage 结构。如果BasePage 执行InitializeComponent(),则XAML 元素在MyPage 内失去作用域。这意味着我不能在没有得到NullReferenceException 的情况下调用MyPage.MyListView.ItemSource = xyz

如果我从BasePage 中禁用InitializeComponent() 调用,那么它会按预期工作。

BasePage.InitializeComponent() 做了什么打破了上述范围?

   Models
   Pages
     ├ BasePage.xaml
     |   ⤷ BasePage.xaml.cs
     └ MyPage.xaml
         ⤷ MyPage.xaml.cs
   Views
   App.xaml
     ⤷ App.xaml.cs

在我的 MyPage.xaml 标记上,我有各种 StackLayout 元素、ListView 等。它们都存在于 pages:BasePage.Content 标记中,如下所示:

<!-- for s/o: MyPage.xaml -->
<?xml version="1.0" encoding="utf-8" ?>
<pages:BasePage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:pages="clr-namespace:Namespace.Pages"
    xmlns:views="clr-namespace:Namespace.Views"
    x:Class="Namespace.Pages.MyPage">

    <pages:BasePage.Content>

        <ListView x:Name="ListViewView">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Image Source="{Binding imageUrl}" />
                            <Label Text="{Binding formattedDayOfWeek}" />
                            <Label Text="{Binding formattedDate}" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </pages:BasePage.Content>

</pages:BasePage>

在我的MyPage.xaml.cs 类中,构造函数执行InitializeComponent() 方法。

BasePage.xaml 的外观如下:

<!-- for s/o: BasePage.xaml -->
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="Namespace.Pages.BasePage"
    x:Name="_parent">

    <ContentPage.Content>
        <StackLayout x:Name="VerticalLayout" BackgroundColor="#f1f1f1">
            <ContentView
                x:Name="cv"
                x:FieldModifier="public"
                HorizontalOptions="FillAndExpand"
                VerticalOptions="FillAndExpand"
                Content="{Binding Path=ViewContent, Source={x:Reference _parent}}" />
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

所以重申一下:

MyPage.xaml.cs 中,我试图在从 REST 服务器异步获取之后调用ListViewView.ItemsSource = SomeDataModel

如果扩展的BasePage.xaml.cs 类在其构造函数中调用InitializeComponent()...我会在设置ItemsSource 时得到NullReferenceException。

如果扩展的BasePage.xaml.cs 类没有在其构造函数中调用InitializeComponent()... ItemsSource 已正确设置并出现列表。

有人可以向我解释这里发生了什么,以便我可以成功初始化所有内容吗?如果我不初始化 BasePage,那么我就无法按我的意愿访问其中的元素。

谢谢!

【问题讨论】:

  • 你能显示代码吗? :)
  • “这不是要理解 NullReferenceException 是什么” -- 然后,在不提及 NullReferenceException 的情况下提出您的问题。真正不询问异常的问题不需要提及,包括解释您在调查 NRE 时发现的信息,并且还包括好 minimal reproducible example 重现问题。
  • 如果您能提供minimal reproducible example,那就太好了。
  • @PeterDuniho 问什么是 NullReferenceException 和为什么抛出它是有区别的。问题基本上是,为什么 X 在这里为空?——除了我们不知道 X 是什么,也不知道“这里”在哪里。这不应该作为重复而关闭,但是马特,你至少必须提供一个堆栈跟踪和它引用的代码,即使它是自动生成的。
  • @PeterDuniho 我同意这个问题是缺乏的,但它可能是一个很好的问题,同时仍然提到 NRE——我宁愿马特继续提到 NRE,因为我想查看堆栈跟踪。我也同意马特在这里提出了错误的问题,但将其标记为骗子是没有意义的——他很明显不打算问 NRE 是什么。他似乎遇到了麻烦,因为他的印象是 InitializeComponent 可以保证避免抛出 NRE 并且不确定如何继续调试它。

标签: c# xamarin xamarin.forms


【解决方案1】:

请记住,BasePage 的构造函数在 MyPage 的构造函数之前被调用。这也意味着 BasePage 的 InitializeComponent 会在 MyPage 的构造函数之前被调用。

调用顺序实际上看起来像这样,所以实际上在后台发生的事情略有不同:

  1. BasePage..ctor
  2. BasePage.InitializeComponent
  3. MyPage..ctor
  4. MyPage.InitializeComponent

这会产生一个依赖问题:BasePage 的 InitializeComponent 方法中的任何内容都不能依赖于由 MyPage 初始化的任何内容。如果是这样,您可能会收到NullReferenceException 或其他意外行为。

如果不查看 C# 代码,很难确切知道错误的根源是什么,但我强烈怀疑 BasePage.InitializeComponent 引用的内容在 MyPage..ctorMyPage.InitializeComponent 运行之前未设置。您可以通过暂时删除对BasePage..ctor 中的BasePage.InitializeComponent 的调用并将其移至MyPage.InitializeComponent 的末尾来轻松测试这一点。

【讨论】:

  • 我理解这个顺序,这就是我感到困惑的原因。出于演示目的,我的 BasePage.xaml.cs 甚至没有在其自己的 XAML 中引用任何内容;它只是在构造函数中调用InitializeComponentMyPage.xaml.cs 仅引用 MyPage.xaml 中的元素...它不会调用 BasePage 中的任何内容。这就是为什么我很困惑,因为我将它们限制在自己的范围内,但是当我让 BasePage 在其构造函数中调用 InitializeComponent 时,MyPage 似乎忘记了它的范围是什么。
  • BasePage.InitializeComponent 绝对不是空的,这几乎肯定是您获得 NRE 的地方。但是,如果您不提供 InitializeComponent 的内容和堆栈跟踪,我将无能为力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
相关资源
最近更新 更多