aloneguid / config

⚙ Config.Net - the easiest configuration framework for .NET developers. No BS.
MIT License
656 stars 86 forks source link

INotifyPropertyChanged doesn't work with Windows Forms DataBinding #151

Open BDizzle opened 1 year ago

BDizzle commented 1 year ago

Hello, we love the project, it is solving several major problems for us and we really appreciate it!

We're using Config.Net in a large Winforms app that relies heavily on DataBinding. One of the biggest reasons we chose this library was the really easy support for INotifyPropertyChanged.

However, once we get it into our project, we found that WinForms databinding doesn't actually work with the INotifyPropertyChanged events that the library raises. We've confirmed that the event is being fired, however the sender argument is always null.

After much debugging between the project's source and the .NET Framework's source, I think I found the issue.

private void TryNotifyInpc(IInvocation invocation, ResultBox rbox)
{
   if (_inpcHandler == null || rbox is MethodResultBox) return;

   _inpcHandler.Invoke(invocation.InvocationTarget, new PropertyChangedEventArgs(rbox.Name));
   if(rbox.Name != rbox.StoreByName)
   {
      //notify on StoreByName as well
      _inpcHandler.Invoke(invocation.InvocationTarget, new PropertyChangedEventArgs(rbox.StoreByName));
   }
}

In the above code, invocation.InvocationTarget is always null. This doesn't impact general use of INotifyPropertyChanged, but deep in the code for System.ComponentModel.ReflectPropertyDescriptor, there is a null check on this value that prevents databinding from catching the event and actually updating the control.

I've forked the repo and created a branch that demos this issue as well as a proposed fix. Changing the event invocation to use invocation.Proxy instead of invocation.InvocationTarget appears to fix the issue. The relevant change to the library is in Core/InterfaceInterceptor.cs.

If you run the project that I added and click the button on the form, it will append a single '1' to the value of the single config option defined (IMySettings.Setting). The textbox on the form is databound to this option, so it should updated immediately. Without my change to the InterfaceInterceptor no update happens.

I'm happy to rework this into a proper PR if you agree that this is a reasonable way to fix this issue. Thanks!