Kenna
Kenna

Reputation: 302

C# - Xamarin.Forms - Dependency Service and event

I would like to be notified with a PropertyChanged event raised from a class MyClass implementing an interface IMyInterface. The instance of this class is retrieved with DependencyService.Get<IMyInterface>();

Now, this is the class (Android project), in which there is a property with a backing field:

class MyClass : IMyInterface {

    private bool _isEnabled;
    public bool IsEnabled
    {
        get { return _isEnabled; }
        private set { _isEnabled = value; OnPropertyChanged("IsEnabled"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    public void OnSomethingHappens() { //This method is called when something particular happens
        /* Some code... */
        IsEnabled = true; //The point where the property is changed
        /* ...some other code */
    }
}

The interface (Forms project) looks like this:

public interface IMyInterface : INotifyPropertyChanged
{
    /* code relating the interface */
}

This interface is implementing INotifyPropertyChanged in order to have the possibility to listen to a property change (as seen in the class above). So far, so good.

The problem is when, in my Forms project, I register an event handler with this:

_myService = DependencyService.Get<IMyInterface>();
_myService.PropertyChanged += (sender, e) => { /* do stuff */ };

But when the property in my implementing class changes, PropertyChanged results null, and this means that the event is never fired.

I would like to add a little thing: recently, I experienced that accessing a non-static list property with DependencyService.Get<IMyInterface>().MyList was useless, since MyList resulted to be of size 0, even if this list was filled inside the implementing class. I solved this using a static property. Maybe this is related to the issue above.

I would like to understand what I am mistaking in order to have this PropertyChanged event working correctly.

Upvotes: 1

Views: 1650

Answers (1)

Kenna
Kenna

Reputation: 302

Ok, I figured out how to solve this. Basically, I created a property with a private static event backing field, as follows:

private static event PropertyChangedEventHandler _propertyChanged;
public PropertyChangedEventHandler PropertyChanged
{
    get { return _propertyChanged; }
    set { _propertyChanged = value; }
}

This way, I could have the following code working properly:

protected void OnPropertyChanged(string name)
{
    _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

Infact, _propertyChanged was not null anymore, since I subscribed to the event with the following code (formally identical to the one posted on my question, with the difference that I used the PropertyChanged property backed with the private static field _propertyChanged):

_myService = DependencyService.Get<IMyInterface>();
_myService.PropertyChanged += (sender, e) => { /* do stuff */ };

Now I think that this was necessary because I am using DependencyService, otherwise, in normal code, this issue should not come out. Anyway, I am guessing if the idea of having a EventHandler property backed with a private static event field is a good code practice or just sounds weird. But it works, and it works pretty good.

But, in order to do all of this, I had to change this:

public interface IMyInterface : INotifyPropertyChanged
{
    /* code relating the interface */
}

to this:

public interface IMyInterface
{
    PropertyChangedEventHandler PropertyChanged { get; set; }
    /* code relating the interface */
}

I had to add that property in IMyInterface so that I could access it from my Forms project code. Moreover, I no more implement INotifyPropertyChanged, because INotifyPropertyChanged asks me to implement the interface with a:

public event PropertyChangedEventHandler PropertyChanged

inside my implementing class, but I substituted it with

private static event PropertyChangedEventHandler _propertyChanged;
public PropertyChangedEventHandler PropertyChanged
{
    get { return _propertyChanged; }
    set { _propertyChanged = value; }
}

as I exposed above.

Upvotes: 1

Related Questions