2
votes

I am attempting to implement a modal confirmation popup using mvvmcross in iOS, following the Stuart's outline in this question. I get the following exception when attempting to bind the InteractionRequest to the Event handler:

Problem seen during binding execution for to ConfirmationInteraction - problem
TargetInvocationException: Exception has been thrown by the target of an invocation.

The inner exception is:

ArgumentNullException: missing source event info in MvxWeakEventSubscription
Parameter name: sourceEventInfo
at Cirrious.CrossCore.WeakSubscription.MvxWeakEventSubscription`2[System.Object,System.EventArgs]..ctor (System.Object source, System.Reflection.EventInfo sourceEventInfo, System.EventHandler`1 targetEventHandler) [0x00000] in <filename unknown>:0 
at Cirrious.CrossCore.WeakSubscription.MvxGeneralEventSubscription..ctor (System.Object source, System.Reflection.EventInfo eventInfo, System.EventHandler`1 eventHandler) [0x00000] in <filename unknown>:0 
at Cirrious.CrossCore.WeakSubscription.MvxWeakSubscriptionExtensionMethods.WeakSubscribe (System.Reflection.EventInfo eventInfo, System.Object source, System.EventHandler`1 eventHandler) [0x00000] in <filename unknown>:0 

Most of the plumbing is identical to the referenced stack overflow question above, but I will post it here for completeness:

public class InteractionRequestedEventArgs : EventArgs
{
    public Action Callback 
    { 
        get; 
        private set; 
    }

    public object Context 
    { 
        get; 
        private set; 
    }

    public InteractionRequestedEventArgs(object context, Action callback)
    {
        Context = context;
        Callback = callback;
    }
}

The InteractionRequest:

public class InteractionRequest<T> : IInteractionRequest
{
    public event EventHandler<InteractionRequestedEventArgs> Raised;

    public void Raise(T context, Action<T> callback)
    {
        var handler = this.Raised;
        if (handler != null)
        {
            handler(
                this, 
                new InteractionRequestedEventArgs(
                context, 
                () => callback(context)));
        }
    }
}

The confirmation class:

public class Confirmation
{
    public string Message { get; private set; }
    public bool Confirmed { get; set; }
    public Confirmation(string message)
    {
        Message = message;
    }
}

In the view model we set up the request as so:

private InteractionRequest<Confirmation> _confirmCancelInteractionRequest = new InteractionRequest<Confirmation>();
    public IInteractionRequest ConfirmCancelInteractionRequest
    {
        get
        {
            return _confirmCancelInteractionRequest;
        }
    }

in the view we set up the event subscription:

    private MvxGeneralEventSubscription _confirmationSubscription;
    private IInteractionRequest _confirmationInteraction;
    public IInteractionRequest ConfirmationInteraction
    {
        get { 
            return _confirmationInteraction; 
        }
        set
        {
            if (_confirmationInteraction == value)
                return;
            if (_confirmationSubscription != null)
                _confirmationSubscription.Dispose();
            _confirmationInteraction = value;
            if (_confirmationInteraction != null)
                _confirmationSubscription = _confirmationInteraction
                    .GetType ()
                    .GetEvent ("Raise")
                    .WeakSubscribe(_confirmationInteraction, DoConfirmation);

        }
    }

The event handler in the view looks like this:

private void DoConfirmation(object s, EventArgs args)
    {
        var iArgs = (InteractionRequestedEventArgs)args;
        var confirmation = (Confirmation)iArgs.Context;

        var alert = new UIAlertView(); 
        alert.Title = "Bazinga"; 
        alert.Message = confirmation.Message; 

        alert.AddButton("Yes"); 
        alert.AddButton("No"); 

        alert.Clicked += (sender, e) => { 
            var alertView = sender as UIAlertView; 
                            // do something with the event
            iArgs.Callback();
        }; 
    }

Finally the binding, which is inside the constructor for the view. The view is a MT Dialog Element, hence the DelayBind():

this.DelayBind(() =>
        {
            var set = this.CreateBindingSet<CustomerElement, CustomerViewModel>();
            ...
            set.Bind().For(my => my.ConfirmationInteraction).To(customer => customer.ConfirmCancelInteractionRequest);
            set.Apply();
        });
    }
1

1 Answers

0
votes

The null reference exception with the stack

at Cirrious.CrossCore.WeakSubscription.MvxWeakEventSubscription`2[System.Object,System.EventArgs]..ctor (System.Object source, System.Reflection.EventInfo sourceEventInfo, System.EventHandler`1 targetEventHandler) [0x00000] in <filename unknown>:0 
at Cirrious.CrossCore.WeakSubscription.MvxGeneralEventSubscription..ctor (System.Object source, System.Reflection.EventInfo eventInfo, System.EventHandler`1 eventHandler) [0x00000] in <filename unknown>:0 
at Cirrious.CrossCore.WeakSubscription.MvxWeakSubscriptionExtensionMethods.WeakSubscribe (System.Reflection.EventInfo eventInfo, System.Object source, System.EventHandler`1 eventHandler) [0x00000] in <filename unknown>:0 

can only occur if _confirmationInteraction.GetType ().GetEvent ("Raise") returns null

So... I think the problem might be that your event is called Raised


If it helps: