using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
namespace Kackman.Framework
{
public sealed class PropertyLink : IDisposable
{
private object m_object1;
private object m_object2;
private string m_propertyName;
public PropertyLink(object object1, object object2, string propertyName)
{
Debug.Assert(object1 != null);
Debug.Assert(object2 != null);
Debug.Assert(string.IsNullOrEmpty(propertyName) == false);
m_object1 = object1;
m_object2 = object2;
m_propertyName = propertyName;
SyncValues(m_object1, m_object2, m_propertyName);
Bind();
}
public object Object1 { get { return m_object1; } }
public object Object2 { get { return m_object2; } }
public string PropertyName { get { return m_propertyName; } }
public static IEnumerable<PropertyLink> LinkProperties(object object1, object object2, string[] propertyNames)
{
Debug.Assert(propertyNames != null);
List<PropertyLink> list = new List<PropertyLink>();
foreach (string propertyName in propertyNames)
list.Add(new PropertyLink(object1, object2, propertyName));
return list;
}
private static void SyncValues(object source, object target, string propertyName)
{
PropertyInfo sourceProperty = source.GetType().GetProperty(propertyName);
Debug.Assert(sourceProperty != null);
Debug.Assert(sourceProperty.CanRead);
Debug.Assert(sourceProperty.CanWrite);
PropertyInfo targetProperty = target.GetType().GetProperty(propertyName);
Debug.Assert(targetProperty != null);
Debug.Assert(targetProperty.CanRead);
Debug.Assert(targetProperty.CanWrite);
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
public void Bind()
{
Bind(m_object1, new EventHandler(Object1_PropertyChanged));
Bind(m_object2, new EventHandler(Object2_PropertyChanged));
}
public void Unbind()
{
Unbind(m_object1, new EventHandler(Object1_PropertyChanged));
Unbind(m_object2, new EventHandler(Object2_PropertyChanged));
}
public void Dispose()
{
Unbind();
GC.SuppressFinalize(this);
}
private void Bind(object o, Delegate d)
{
EventInfo e = o.GetType().GetEvent(m_propertyName + "Changed");
Debug.Assert(e != null);
e.AddEventHandler(o, d);
}
private void Unbind(object o, Delegate d)
{
EventInfo e = o.GetType().GetEvent(m_propertyName + "Changed");
Debug.Assert(e != null);
e.RemoveEventHandler(o, d);
}
private void Object1_PropertyChanged(object sender, EventArgs args)
{
Unbind(m_object2, new EventHandler(Object2_PropertyChanged));
SyncValues(m_object1, m_object2, m_propertyName);
Bind(m_object2, new EventHandler(Object2_PropertyChanged));
}
private void Object2_PropertyChanged(object sender, EventArgs args)
{
Unbind(m_object1, new EventHandler(Object1_PropertyChanged));
SyncValues(m_object2, m_object1, m_propertyName);
Bind(m_object1, new EventHandler(Object1_PropertyChanged));
}
}
}