简体   繁体   中英

EventHandler called once without event fired

EventHandler called once without event fired


    public class Observable<T>
    {
        public delegate void ValueChanged(T value);
        event ValueChanged Changed;

        public T Value { get; private set; }

        public Observable(T t)
        {
            Value = t;
        }
        /*
        public void Set(T value)
        {
            if (Equals(value, Value))
            {
                return;
            }
            Value = value;
            Changed?.Invoke(Value);
        }
        */

        public void Subscribe(ValueChanged action)
        {
            Changed += action;
        }
    }


I am currently seeing the issue in the user permission handling of a Xamarin mobile app I am working on

ViewModel reads local storage to get latest saved permission (mobile). It creates the Obervable<Permisson> property passing the saved value in the constructor:

var savedCamera = HistoryService.GetStatus<Permissions.Camera>()
CameraPermissionProperty = new Observable<PermissionStatus>(savedCamera); // <--

Then subscription is made

CameraPermissionProperty.Subscribe(SendPermission<Permissions.Camera>);

The SendPermission<Permissions.Camera> method is triggered once with value set in the Observable despite not having invoked the ValueChanged delegate.

I can't repoduce this in a console app.

What could be the issue, could be related to threading?


I added a number to see which method was called:


// ... Observable

public delegate void ValueChanged(T value, int number); //<--

event ValueChanged Changed;

public void Subscribe(ValueChanged action)
{
    Changed += action;
    Number = 18;
}

public void SubscribeWithInitialUpdate(ValueChanged action)
{
    Changed += action;
    Number = 10;
    Changed.Invoke(Value, Number);
            
}

10 is returned even though I am calling the Subscribe method

I could not reproduce your error in Xamarin, so I will try to provide some suggestions.

First here is the code I tested:

public class Observable<T>
{
    public delegate void ValueChanged(T v, int n);
    public event ValueChanged Changed;

    public T Value { get; private set; }

    public int Number; //this was missing in your code example
    public Observable(T t)
    {
        Value = t;
    }
    
    public void Set(T value)
    {
        if (Equals(value, Value))
        {
            return;
        }
        Value = value; //breakpoint here
        Changed?.Invoke(Value, Number);
    }
    
    public void Subscribe(ValueChanged action)
    {
        Changed += action;
        Number = 22; //breakpoint here
        Console.WriteLine("setting 22");
    }

    public void SubscribeWithInitialUpdate(ValueChanged action)
    {
        Changed += action;
        Number = 11; //breakpoint here
        Console.WriteLine("setting 11 - is never called");
        Changed?.Invoke(Value, Number);
    }
}

I executed the code from an arbitrary viewmodel's c-tor:

public class SomeViewModel // : INotifyPropertyChanged
{
        public SomeViewModel()
    {
        obs = new Observable<string>("baar");
        // subscribe to event with anonymous delegate event handler
        obs.Subscribe((v,n) => { //breakpoint here
            Console.WriteLine("value=" + v + " number=" + n); //breakpoint here
        });
        obs.Set("foo"); //breakpoint here
    }
}
    //console output:
    //setting 22
    //value=foo number=22

In Xamarin Forms, you can use breakpoints and Console.WriteLine in DEBUG mode with the Android Emulator. For me this was working as expected. So I suggest setting breakpoints at the relevant places, especially the method that should not be called, but somehow is ("SubscribeWithInitialUpdate"), maybe you will catch, when it is called. In my scenario the method was never executed, as expected.

For me this has nothing to do with invoking the event. Number = 10 is set in the method SubscribeWithInitialUpdate(), which is independent from the event. Even if the event would have been invoked from some other method multiple times, the breakpoint in that method should never be reached.

It may be that your SendPermission<Permissions.Camera> method is called from somewhere else, not from the event (though the 10 would still be a mystery). So I suggest to add a breakpoint in there aswell. Also to be sure, don't add a method than can be called as a parameter, try adding an anonymous lambda delegate (at least for debugging), so you can be sure, no other caller exists.

So my last suggestion is to try my code in a new empty Xamarin project and compare that to your project.

I am assuming you don't want to do MVVM here and use custom listeners? Otherwise I would suggest to simply implement INotifyPropertyChanged. Examples: Link1 Link2 Link3

I hope some of this helps.

If you are using multiple threads, I assume you know what you are doing, otherwise I don't know why or how something would ever call any arbitrary method. You could check it's thread.ManagedThreadId Link

You might think about of the loading of page. It could be launched on page load

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM