EventToCommand Behavior Null Reference iOS

LJongLJong NLMember ✭✭✭

Hey all,

I am currently struggling to find a solution to a problem I am facing. I have a couple of behaviors attached to certain pages in my app and when I navigate back and forth it doesn't matter to which page it crashes the app. I get the following error output:

2017-01-27 11:14:46.878 BNApp.iOS[2888:22873] 
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
  at BNApp.Behaviors.EventToCommandBehavior.DeregisterEvent (System.String name) [0x0001e] in C:\TFS\BN\BNApp\BNApp\BNApp\BNApp\Behaviors\EventToCommandBehavior.cs:83 
  at BNApp.Behaviors.EventToCommandBehavior.OnDetachingFrom (Xamarin.Forms.VisualElement bindable) [0x00009] in C:\TFS\BN\BNApp\BNApp\BNApp\BNApp\Behaviors\EventToCommandBehavior.cs:51 
  at Xamarin.Forms.Behavior`1[T].OnDetachingFrom (Xamarin.Forms.BindableObject bindable) [0x00000] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\Behavior.cs:57 
  at Xamarin.Forms.Behavior.Xamarin.Forms.IAttachedObject.DetachFrom (Xamarin.Forms.BindableObject bindable) [0x00000] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\Behavior.cs:27 
  at Xamarin.Forms.AttachedCollection`1[T].OnDetachingFrom (Xamarin.Forms.BindableObject bindable) [0x0000f] in C:\BuildAg
ent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\AttachedCollection.cs:75 
  at Xamarin.Forms.AttachedCollection`1[T].DetachFrom (Xamarin.Forms.BindableObject bindable) [0x00000] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\AttachedCollection.cs:32 
  at Xamarin.Forms.VisualElement.Finalize () [0x0001d] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\VisualElement.cs:789 
2017-01-27 11:14:46.879 BNApp.iOS[2888:22873] Unhandled managed exception:
Object reference not set to an instance of an object (System.NullReferenceException)
  at BNApp.Behaviors.EventToCommandBehavior.DeregisterEvent (System.String name) [0x0001e] in C:\TFS\BN\BNApp\BNApp\BNApp\BNApp\Behaviors\EventToCommandBehavior.cs:83 
  at BNApp.Behaviors.EventToCommandBehavior.OnDetachingFrom (Xamarin.Forms.VisualElement bindable) [0x00009] in C:\TFS\BN\BNApp\BNApp\BNApp\BNApp\Behaviors\EventToCommandBehavior.cs:51 
  at Xamarin.Forms.Behavior`1[T].OnDetachingFrom (Xamarin.Forms.BindableObject bindab
le) [0x00000] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\Behavior.cs:57 
  at Xamarin.Forms.Behavior.Xamarin.Forms.IAttachedObject.DetachFrom (Xamarin.Forms.BindableObject bindable) [0x00000] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\Behavior.cs:27 
  at Xamarin.Forms.AttachedCollection`1[T].OnDetachingFrom (Xamarin.Forms.BindableObject bindable) [0x0000f] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\AttachedCollection.cs:75 
  at Xamarin.Forms.AttachedCollection`1[T].DetachFrom (Xamarin.Forms.BindableObject bindable) [0x00000] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\Interactivity\AttachedCollection.cs:32 
  at Xamarin.Forms.VisualElement.Finalize () [0x0001d] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Core\VisualElement.cs:789 
2017-01-27 11:14:46.880 BNApp.iOS[2888:22873] critical: Stacktrace:

2017-01-27 11:14:46.880 BNApp.iOS[2888:22873] critical: 
Native stacktrace:
2017-01-27 11:14:46.972 BNApp.iOS[2888:22873] critical:     0   BNApp.iOS                           0x00000001045a125d mono_handle_native_sigsegv + 253
2017-01-27 11:14:46.972 BNApp.iOS[2888:22873] critical:     1   libsystem_platform.dylib            0x00000001115a152a _sigtramp + 26
2017-01-27 11:14:46.972 BNApp.iOS[2888:22873] critical:     2   ???                                 0x0000000104fb699b 0x0 + 4378552731
2017-01-27 11:14:46.973 BNApp.iOS[2888:22873] critical:     3   libsystem_c.dylib                   0x00000001112fefd7 abort + 129
2017-01-27 11:14:46.973 BNApp.iOS[2888:22873] critical:     4   BNApp.iOS                           0x000000010472de5f xamarin_unhandled_exception_handler + 47
2017-01-27 11:14:46.973 BNApp.iOS[2888:22873] critical:     5   BNApp.iOS                           0x00000001045fd55b mono_invoke_unhandled_exception_hook + 139
2017-01-27 11:14:46.973 BNApp.iOS[2888:22873] critical:     6   BNApp.iOS                           0x00000001046a3b9c mono_thread_internal_unhandled_exception + 156
2017-01-27 11:14:46.973 BNApp.iOS[2888:22873] critical:     7   BNApp.iOS                           0x00000001045fffdb mono_gc_run_finalize + 1099
2017-01-27 11:14:46.973 BNApp.iOS[2888:22873] critical:     8   BNApp.iOS                           0x00000001046c3dbc sgen_gc_invoke_finalizers + 220
2017-01-27 11:14:46.974 BNApp.iOS[2888:22873] critical:     9   BNApp.iOS                           0x0000000104601b2a finalizer_thread + 618
2017-01-27 11:14:46.974 BNApp.iOS[2888:22873] critical:     10  BNApp.iOS                           0x00000001046a4483 start_wrapper + 339
2017-01-27 11:14:46.974 BNApp.iOS[2888:22873] critical:     11  BNApp.iOS                           0x000000010470dc72 inner_start_thread + 354
2017-01-27 11:14:46.974 BNApp.iOS[2888:22873] critical:     12  libsystem_pthread.dylib             0x00000001115b399d _pthread_body + 131
2017-01-27 11:14:46.974 BNApp.iOS[2888:22873] critical:     13  libsystem_pthread.dylib             0x00000001115b391a _pthread_body + 0
2017-01-27 11:14:46.974 BNApp.iOS[2888:22873] critical:     14  libsystem_pthread.dylib             0x00000001115b1351 thread_start + 13
2017-01-27 11:14:46.975 BNApp.iOS[2888:22873] critical: 
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.

I am using the code sample for reusable EventToCommand behavior found here:

https://github.com/xamarin/xamarin-forms-samples/tree/master/Behaviors/EventToCommandBehavior

I have modified my solution a little bit by setting the T not to view but VisualElement.

public class EventToCommandBehavior : BehaviorBase<VisualElement>
    {
       private Delegate _eventHandler;

        public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
        public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
        public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
        public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);

        public string EventName
        {
            get { return (string)GetValue(EventNameProperty); }
            set { SetValue(EventNameProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public IValueConverter Converter
        {
            get { return (IValueConverter)GetValue(InputConverterProperty); }
            set { SetValue(InputConverterProperty, value); }
        }

        protected override void OnAttachedTo(VisualElement bindable)
        {
            base.OnAttachedTo(bindable);
            RegisterEvent(EventName);
        }

        protected override void OnDetachingFrom(VisualElement bindable)
        {
            base.OnDetachingFrom(bindable);
            DeregisterEvent(EventName);
        }

        public void RegisterEvent(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                return;
            }

            var eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
            if (eventInfo == null)
            {
                throw new ArgumentException($"EventToCommandBehavior: Can't register the '{EventName}' event.");
            }
            var methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
            _eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
            eventInfo.AddEventHandler(AssociatedObject, _eventHandler);
        }

        public void DeregisterEvent(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                return;
            }

            if (_eventHandler == null)
            {
                return;
            }

            var eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
            if (eventInfo == null)
            {
                throw new ArgumentException($"EventToCommandBehavior: Can't de-register the '{EventName}' event.");
            }
            eventInfo.RemoveEventHandler(AssociatedObject, _eventHandler);
            _eventHandler = null;
        }

       public void OnEvent(object sender, object eventArgs)
        {
            if (Command == null)
            {
                return;
            }

            object resolvedParameter;
            if (CommandParameter != null)
            {
                resolvedParameter = CommandParameter;
            }
            else if (Converter != null)
            {
                resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
            }
            else
            {
                resolvedParameter = eventArgs;
            }

            if (Command.CanExecute(resolvedParameter))
            {
                Command.Execute(resolvedParameter);
            }
        }

      public static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var behavior = (EventToCommandBehavior)bindable;
            if (behavior.AssociatedObject == null)
            {
                return;
            }

            var oldEventName = (string)oldValue;
            var newEventName = (string)newValue;

            behavior.DeregisterEvent(oldEventName);
            behavior.RegisterEvent(newEventName);
        }
    }
}

I hope someone could help me find a solution to this annoying issue. This whole problem does not exist on Android so I am kind of suprised that it throws these errors on iOS.

Cheers,

Luuk

Answers

Sign In or Register to comment.