samedi 6 juin 2015

Fire INotifyPropertyChanged.PropertyChanged via Reflection

I'm trying to fire PropertyChanged via reflection and I'm having some issues.

The following code works:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string m_test = string.Empty;

    public string Test
    {
        get
        {
            return m_test;
        }
        set
        {
            m_test = value;
            Notify();
        }
    }

    protected void Notify([CallerMemberName] string name = null)
    {
        var handler = PropertyChanged;
        if (handler != null && name != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

public class ViewModel : ViewModelBase
{
    private string m_test2 = string.Empty;
    public string Test2
    {
        get
        {
            return m_test2;
        }
        set
        {
            m_test2 = value;
            Notify();
        }
    }
}

However, I have added an extension method to INotifyPropertyChanged that would raise it via reflection.

Instead of Notify() I could call this.Notify() instead, which is defined like so:

    /// <summary>
    /// Invoke sender's PropertyChanged event via Reflection
    /// </summary>
    /// <param name="sender">sender of the event</param>
    /// <param name="prop">The Property name that has changed</param>
    public static void NotifyPropertyChanged(this INotifyPropertyChanged sender, [CallerMemberName] string prop = null)
    {
        var senderType = sender.GetType();
        var eventInfo = senderType.GetEvent("PropertyChanged");
        var methodInfo = senderType.GetField("PropertyChanged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        if (methodInfo != null)
        {
            var delegates = (MulticastDelegate)methodInfo.GetValue(sender);
            if (delegates != null)
            {
                foreach (var handler in delegates.GetInvocationList())
                {
                    handler.Method.Invoke(handler.Target, new object[] { sender, new PropertyChangedEventArgs(prop) });
                }
            }
        }
    }

Unfortunately, GetField returns null for ViewModel in the example above.

Is there a way to reflect the parent's event?

I'm thinking of iterating over the base classes, but I'm hoping for a better/easier way.





Aucun commentaire:

Enregistrer un commentaire