Xamarin Forms - Droid:自定义选取器对话框导致异常:对象引用未设置为对象的实例

Xamarin Forms - Droid: Custom Picker's Dialog causing Exception: Object reference not set to an instance of an object

提问人:Thunderlight 提问时间:7/7/2018 最后编辑:Super JadeThunderlight 更新时间:1/6/2019 访问量:859

问:

背景描述

我正在使用 Visual Studio for Mac 开发跨平台移动应用程序。 该项目的 Xamarin.Forms 版本为 3.1.0.583944(这是最新的可用版本)。对于 Android,所有入口组件都有一个线条,而不是一个框的线 (_____),因此(并且作为要求)创建了一个自定义渲染来更改组件的外观。

在项目文件夹中,创建了 CustomPicker.cs:

using System;
using Xamarin.Forms;

namespace Project
{
    public class CustomPicker : Picker
    {
        public Color BorderColor { get; set; } = Color.Black;
    }
}

在 Project.Droid 文件夹中,创建了 CustomPickerRenderer.cs:

using System;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Views;
using Project;
using Project.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(CustomPicker), typeof(CustomPickerRenderer))]
namespace Project.Droid
{
    public class CustomPickerRenderer : PickerRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                var customPicker = (CustomPicker)e.NewElement;
                GradientDrawable gd = new GradientDrawable();
                gd.SetColor(Android.Graphics.Color.Transparent);
                gd.SetStroke(2, customPicker.BorderColor.ToAndroid());
                this.Control.SetBackground(gd);
                this.Control.SetTextColor(e.NewElement.TextColor.ToAndroid());
                this.Control.SetHintTextColor(Android.Graphics.Color.Gray);
            }
        }
    }
}

xaml 文件仅包含 CustomPicker 元素:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:signature="clr-namespace:SignaturePad.Forms;assembly=SignaturePad.Forms"  xmlns:res="clr-Project" x:Class="Poject.View"  xmlns:local="clr-Project;assembly=Project">
    <ContentPage.Content>
        <local:CustomPicker x:Name="action_picker" TextColor="Black" Title="Seleccione la acción" BorderColor="#3D7C00" IsEnabled="false" ItemsSource="{Binding Actions}" ItemDisplayBinding="{Binding text}" SelectedIndexChanged="OnActionChange" SelectedItem="{Binding SelectedAction}" />
    </ContentPage.Content>
</ContentPage>

问题

在测试自定义选取器时,我得到了所需的结果;选取器使用框状边框(而不是下划线)和一些其他颜色内容正确呈现。仅当测试了“所需”功能时,该组件才按预期工作(单击组件,等待弹出包含选项的对话框,单击选项,然后单击确定按钮)。当由于任何原因中断对话时,会出现此问题。例如,我单击组件,当弹出选项对话框时,我单击后退按钮 - 然后对话框显示在另一个视图中,当点击选项或按钮时,会引发异常。(另一种情况发生在对话框打开时,我从顶部滑动屏幕以打开配置和通知菜单,然后返回到应用程序)。异常 StackTrace 如下所示:

未处理的异常: System.NullReferenceException:对象引用未设置为对象的实例。 在 Xamarin.Forms.Platform.Android.PickerRenderer+<>c__DisplayClass12_0.b__0 (System.Object s、Android.Content.DialogClickEventArgs a)[0x00000] 在 D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\PickerRenderer.cs:135

at Android.Content.IDialogInterfaceOnClickListenerImplementor.OnClick

(Android.Content.IDialogInterface 对话框,System.Int32 其中) [0x0000a] 在 /Users/builder/data/lanes/5809/a7829590/source/monodroid/external/xamarin-android/src/Mono.Android/obj/Release/android-27/mcw/Android.Content.IDialogInterface.cs:250

at Android.Content.IDialogInterfaceOnClickListenerInvoker.n_OnClick_Landroid_content_DialogInterface_I

(System.IntPtr jnienv、System.IntPtr native__this、System.IntPtr native_dialog, System.Int32 其中) [0x00010] 在 /Users/builder/data/lanes/5809/a7829590/source/monodroid/external/xamarin-android/src/Mono.Android/obj/Release/android-27/mcw/Android.Content.IDialogInterface.cs:201

at (wrapper dynamic-method) System.Object.b72d5cd8-e4b0-403b-a87c-7a28c7960847(intptr,intptr,intptr,int)

尝试过的内容

在网上搜索,我找到了许多可能的解决方案,但不幸的是,没有一个对我有用:

问题

  1. 如何处理此异常?
  2. 自定义选取器渲染器实现是否可行而不会发生此崩溃,或者我是否会被迫使用原始组件?
  3. 有没有办法访问错误堆栈 (Xamarin.Forms.Platform.Android.PickerRenderer+<>c__DisplayClass12_0.) 中描述的 OnClick 事件?

在此问题上的任何帮助将不胜感激。提前感谢所有愿意花时间阅读这篇长文并尝试提供帮助的人。

C# Xamarin Xamarin.Android NullReferenceException

评论

1赞 Hichame Yessou 7/7/2018
在 Android 上,您可以在自定义渲染器中使用 SetOnClickListener 实现 OnClick 事件,这里有一个示例:github.com/XAM-Consulting/FreshEssentials/blob/master/src/Droid/...
2赞 Thunderlight 12/8/2018
@mikecamimo我所做的是删除自定义选取器并使用默认选取器。后来我意识到崩溃是由于对话框而发生的。因此,我所做的是在显示对话框之前检查应用程序是否在后台(因此,仅当应用程序当前在前台处于活动状态时才会显示)。我刚刚在 onStart、onStop、onPause 和 onResume 方法上添加了一个标志来检查应用程序的当前状态。这样做可以防止应用程序在对话框外观中断时崩溃。我希望这对你有所帮助。如果您需要更多信息,请告诉我。
1赞 mikecamimo 1/3/2019
我终于能够重现这个问题了。就我而言,我弹出了选择器,但我没有禁用页面底部的导航栏。有人可以弹出选取器,但在它显示之前,他们可以从导航栏中选择另一个页面。这会将当前页面替换为其他页面,当他们从选取器中选择仍然可见的项目时,将导致异常,因为该页面不再存在。感谢您的帮助@Thunderlight :)
1赞 Thunderlight 1/4/2019
@mikecamimo 对不起,我无法立即回答,但我很高兴您可以重现该问题。为了回答你之前的问题,我的选择器中没有很多项目,但对我有用的是将应用程序部署在低预算的手机中(这显然更慢),这让我有机会中断事件,并导致崩溃。如果您要解决问题,请告诉我您是如何实现这一目标的。也欢迎你,很高兴我能帮助你。
1赞 Thunderlight 1/4/2019
@mikecamimo 关于第二个问题,我像这样处理了 App.cs 文件中的标志: 在显示弹出窗口时,只需检查标志即可了解应用程序是在前台还是后台。希望这对你有所帮助。protected override void OnStart() { Global.AppInBackground = false; }protected override void OnSleep() { Global.AppInBackground = true; }protected override void OnResume() { Global.AppInBackground = false; }

答: 暂无答案