2

I have created a test project as a POC for this problem.

I have a WPF app, that when we use interceptors around the view models, it's stopping the propagation of events. If I disable all interceptors, it works fine.

Here is the code:

MyInterceptor.cs

public class MyInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();
    }
}

IoCTestViewModel.cs

public interface IIoCTestViewModel : INotifyPropertyChanged
{
    int Number { get; }
}

public class IoCTestViewModel : IIoCTestViewModel
{
    public IoCTestViewModel()
    {
        var timer = new Timer(200);
        timer.Elapsed += (a, b) => {
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Number"));
            }
        };
        timer.Start();
    }

    public int Number
    {
        get
        {
            return new Random().Next(1, 100);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

IoCTest.xaml.cs

public partial class IoCTest : UserControl
{
    public IIoCTestViewModel ViewModel { get; set; }

    public IoCTest(IIoCTestViewModel viewModel)
    {
        InitializeComponent();

        DataContext = viewModel;
    }
}

App.xaml (fragment)

        Container = new WindsorContainer();
        Container.Register(Component.For<MyInterceptor>().ImplementedBy<MyInterceptor>());
        Container.Register(Component.For<IIoCTestViewModel>().ImplementedBy<IoCTestViewModel>().Interceptors<MyInterceptor>());
        Container.Register(Component.For<IoCPage>().ImplementedBy<IoCTest>()); //IoCTest is a usercontrol

OK. So once I get an instance of IoCTest and add it to a page, I don't see any changes, even though I am sending PropertyChanged every 200ms. If I remove the interceptor, everything works fine.

So how do I fix this?

Camron B
  • 1,650
  • 2
  • 14
  • 30
  • I believe your PropertyChange notifications are occurring but they have the wrong source. You are passing `this` (i.e. your `IoCTestViewModel`) but WPF knows nothing of that and will not be watching it for changes - it will be watching the proxy that Windsor has generated. – Phil Degenhardt Mar 04 '16 at 01:23
  • I think the same issue is covered here: http://stackoverflow.com/questions/5918707/castle-windsor-proxies-implicit-interfaces-and-wpf-binding – Phil Degenhardt Mar 04 '16 at 01:25
  • @PhilDegenhardt I believe you are correct. Any idea how to fix it? and the link you posted is an implementation to avoid INPC code in classes, which I don't want. I also tried that solution, and it didn't work. – Camron B Mar 04 '16 at 18:19
  • Try `Container.Register(Component.For().ImplementedBy().Interceptors());` – Phil Degenhardt Mar 04 '16 at 22:00
  • @PhilDegenhardt ...What? It works now... Can you please add an answer so I can accept it? And would you do me a favor and explain how this made it work? I'm flabbergasted... – Camron B Mar 04 '16 at 22:27

1 Answers1

1

The issue here is that because you declare your service to be IIoCTestViewModel, when you add an interceptor Windsor simply creates a dynamic proxy that delegates all calls to your implementation type. However, the interception is done using composition - one object delegating to another. Hence, when you raise your property changed event with a sender of this, it is a different object to the one that WPF thinks it is watching.

You should instead register your view model like this:

Container.Register(Component.For<IIoCTestViewModel,IoCTestViewModel>().Implemen‌​tedBy<IoCTestViewModel>().Interceptors<MyInterceptor>())

By specifying multiple services, one of which is actually your implementation class, Windsor will instead generate a class proxy - i.e. the interception will be done using inheritance, with the generated proxy inheriting from IoCTestViewModel. (This is known as type forwarding in Windsor). Now when you raise your event with a sender of this it correctly refers to the same instance that WPF is watching.

See here for a more detailed explanation of type forwarding and its implications for proxies

Phil Degenhardt
  • 7,215
  • 3
  • 35
  • 46