Reputation: 147
I've recently started using interception in the Unity application block and have an perplexing problem with attempting to get nested properties to alert that they have been changed from within the a model in a view model. For example I have a mode that has a System.Drawing.Point as a public property. In the view model I have a public property that returns a string format to present the point as a valid and legible value. However I think I’ve not registered the interception correctly or the end goal is not possible with Unity interception.
I’ve registered interception with my container and setup a policy to intercept all virtual methods and set the rule to catch on all set events – for the life of me though I’m stumped on how to trigger the view model to detect/know that the model property has changed. I suppose the “easy” solution would be to bind the view model to the property on the model specifically and then use a custom formatter in the UI to ensure that the values are displayed correctly though.
If anyone can give some pointers regarding unity interception that would be grand.
Container.AddNewExtension<Interception>();
PolicyDefinition policyDefinition =
Container.Configure<Interception>()
.SetInterceptorFor<MyModel>(new VirtualMethodInterceptor())
.SetInterceptorFor<MyViewModel>(new VirtualMethodInterceptor())
.AddPolicy("NotifyPolicy");
policyDefinition.AddMatchingRule(new PropertyMatchingRule("*", PropertyMatchingOption.Set));
public class MyModel
{
[NotifyPropertyChanged]
public virtual Point APoint { get; set; }
}
public class MyViewModel
{
private MyModel _myModel;
public MyViewModel()
{
_myModel = new MyModel { APoint = new Point(3, 2) };
// {12,8} is not reflected in the UI
_myModel.APoint = new Point(12, 8);
}
[NotifyPropertyChanged]
public virtual string ModelLocation
{
get
{
return string.Format("'{0}, {1}'", _myModel.APoint.X, _myModel.APoint.Y);
}
}
}
I’ve used the NotifyPropertyChangedAttribute and NotifyPropertyChangedHandler from http://www.codeproject.com/Articles/140042/Aspect-Examples-INotifyPropertyChanged-via-Aspects as an example to wire up things up; I’ve included the methods for reference only.
[AttributeUsage(AttributeTargets.Property)]
public class NotifyPropertyChangedAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new NotifyPropertyChangedHandler();
}
}
internal class NotifyPropertyChangedHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
var result = getNext()(input, getNext);
if (input.MethodBase.Name.StartsWith("set_"))
{
var propertyName = input.MethodBase.Name.Substring(4);
var pi = input.Target.GetType().GetProperty(propertyName);
if (pi.HasAttribute<NotifyPropertyChangedAttribute>())
{
var baseType = input.Target.GetType().BaseType;
if (baseType != null)
{
var info =
baseType.GetFields(
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
.FirstOrDefault(f => f.FieldType == typeof(PropertyChangedEventHandler));
if (info != null)
{
var propertyChangedEventHandler = info.GetValue(input.Target) as PropertyChangedEventHandler;
if (propertyChangedEventHandler != null)
propertyChangedEventHandler.Invoke(
input.Target.GetType(), new PropertyChangedEventArgs(propertyName));
}
}
}
}
return result;
}
public int Order { get; set; }
}
Upvotes: 2
Views: 860
Reputation: 3512
When you register your view model, it's not enough just to do that the virtual method interceptor, you also need to register it for policy injection using the PolicyInjectionInterceptor (I think).
I'd however seriously recommend looking at NotifyPropertyWeaver which will give you INotifyPropertyChanged functionality at compile time without the need for a Unity policy.
Upvotes: 3