【问题标题】:Xamarin.Forms Java.Lang.NullPointerException when ContentPage has SizeChanged event listener当 ContentPage 具有 SizeChanged 事件侦听器时,Xamarin.Forms Java.Lang.NullPointerException
【发布时间】:2020-05-11 10:12:12
【问题描述】:

当我尝试覆盖 Xamarin.Forms ContentPage.Content 时收到以下错误消息。

如果新的ContentPage 具有SizeChanged 事件侦听器,我只会收到消息。

Java.Lang.NullPointerException
  Message=Attempt to read from field 'int android.view.ViewGroup$LayoutParams.width' on a null object reference

我要加载的 ContentPage 的代码

    public class ShowSizePage : ContentPage
    {
        readonly Label label;
        public ShowSizePage()
        {
            label = new Label
            {
                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
                Text = "initialized",
            };

            SizeChanged += OnPageSizeChanged;
            Content = label;
        }
        void OnPageSizeChanged (object sender, EventArgs args)
        {
            label.Text = String.Format("{0} \u00D7 {1}", Width, Height);
        }

    }

来自上述 ContentPage 调用者的代码

// Part of an other ContentPage
        void OnShowSizeClicked (object sender, EventArgs args)
        {
            ContentPage c = new ShowSizePage();

            Content = c.Content; // Exception is caused here
        }

如果我直接从我的MainPage 调用ShowSizePage,我不会收到异常。

为了避免异常,我必须进行哪些更改?

编辑最小可重现示例代码:

using System;
using Xamarin.Forms;

namespace NP_Exception
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            // Change this to false to see that ShowSizePage works properly if not loaded through MenuPage
            bool showMenu = true;

            if (showMenu)
                MainPage = new MenuPage(); // Throws exception
            else
                MainPage = new ShowSizePage(); // Works
        }
    }

    public class MenuPage : ContentPage
    {
        readonly StackLayout menu = new StackLayout();
        readonly ScrollView menuView = new ScrollView();
        public MenuPage ()
        {
            Button showSizeButton = new Button { Text = "Show Size" };
            showSizeButton.Clicked += OnShowSizeClicked;
            menu.Children.Add(showSizeButton);

            Button showLabelButton = new Button { Text = "Show Label" };
            showLabelButton.Clicked += OnShowLabelClicked;
            menu.Children.Add(showLabelButton);

            menuView.Content = menu;

            Content = menuView;
        }    
        void OnShowSizeClicked(object sender, EventArgs args)
        {
            ContentPage c = new ShowSizePage();

            Content = c.Content; // Exception is caused here
        }

        void OnShowLabelClicked(object sender, EventArgs args)
        {
            ContentPage c = new ShowLabelPage();

            Content = c.Content;
        }

        protected override bool OnBackButtonPressed()
        {
            Content = menuView;

            return true;
        }
    }
    public class ShowSizePage : ContentPage
    {
        readonly Label label;
        public ShowSizePage()
        {
            label = new Label
            {
                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
                Text = "initialized",
            };

            SizeChanged += OnPageSizeChanged;
            Content = label;
        }
        void OnPageSizeChanged(object sender, EventArgs args)
        {
            label.Text = String.Format("{0} \u00D7 {1}", Width, Height);
        }

    }
    public class ShowLabelPage : ContentPage {
        public ShowLabelPage ()
        {
            Content = new Label { Text = "Hello World! Press hardware back button for menu." };
        }
    }
}

更新: 异常发生在 Xamarin.Forms v4.4.0.991265 但似乎在 v4.6.0.726 中得到修复

【问题讨论】:

  • 您能给我们提供一个最小的、可重现的例子吗?当我没有重现问题时,我使用了您的代码。 OnPageSizeChanged 不会引发。我在 Github 中找到了一个issue,和你的问题类似,你可以看看。
  • @JackHua-MSFT 我添加了一个最小的可重现示例。
  • 我这边还是看不到异常,我上传了我的测试项目here
  • @JackHua-MSFT 我克隆了您的解决方案,它显示标签“已初始化”而不是屏幕尺寸。如果您设置showMenu=false,您将看到SizeChanged 事件被调用。无论如何,即使代码相同,我们的解决方案似乎也有所不同。我将不得不对我们的两个解决方案运行 git diff 以查看您的解决方案有什么不同。我会及时通知你的。感谢您的努力。
  • 是的,我想你可以检查一下我们使用的 Xamarin.form 的版本是否相同。

标签: c# xamarin xamarin.forms


【解决方案1】:

我找到了一个解决方案,可以在获得所需结果的同时摆脱异常。

我必须将页面内容包装到 ContentView 并将 SizeChanged 事件绑定到 ContentView

工作代码示例

    public class ShowSizePage : ContentPage
    {
        readonly Label label;
        public ShowSizePage()
        {
            label = new Label
            {
                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
                Text = "initialized",
            };

            // Wrap Content in ContentView to avoid Exception
            ContentView view = new ContentView { Content = label };

            // Bind SizeChanged event to view
            view.SizeChanged += OnPageSizeChanged;

            // Set View as Content
            Content = view;
        }
        void OnPageSizeChanged(object sender, EventArgs args)
        {
            // Use Width & Height of the sender object
            View view = (View)sender;

            label.Text = String.Format("{0} \u00D7 {1}", view.Width, view.Height);
        }
    }

【讨论】:

  • 不错!一个问题,如果您只想要页面中的内容,为什么不直接使用 ContentView 呢?您可以将ContentView 用作其他主页的Content
  • @pinedax 我想我尝试在调用元素上使用ContentView,但它要么崩溃,要么没有正确计算SizeChanged 尺寸。在我真正的解决方案中,我通过反射包含页面,所以我希望尽可能保持所有内容的开放。我刚从 C# 开始,所以我很感谢我能得到的每一个建议。
【解决方案2】:

此问题已在最新版本的 Xamrin.forms v4.6.0.726 中得到修复。任何在早期版本中遇到此问题的人都可以更新您的Xamarin.Forms 来解决它。

【讨论】:

    猜你喜欢
    • 2018-09-04
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-27
    • 2011-01-11
    • 2022-01-10
    相关资源
    最近更新 更多