Reputation: 1830
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?
Upvotes: 2
Views: 249
Reputation: 7264
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>().ImplementedBy<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
Upvotes: 1