Skip to content

Instantly share code, notes, and snippets.

@sakapon
Last active July 4, 2016 09:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sakapon/ae510350fb5f7b910ba9dc031403a1d9 to your computer and use it in GitHub Desktop.
Save sakapon/ae510350fb5f7b910ba9dc031403a1d9 to your computer and use it in GitHub Desktop.
BindingSample / DynamicBindingWpf / DynamicSyncProxy
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace DynamicBindingWpf
{
public static class DynamicSyncProxy
{
public static DynamicSyncProxy<T> ToDynamicSyncProxy<T>(this T target, int intervalInMilliseconds = 1000) =>
new DynamicSyncProxy<T>(target, intervalInMilliseconds);
public static bool IsIndexer(this PropertyInfo property) =>
property.Name == "Item" && property.GetIndexParameters().Length > 0;
}
public class DynamicSyncProxy<T> : DynamicObject, INotifyPropertyChanged
{
T Target;
Dictionary<string, PropertyInfo> Properties;
Dictionary<string, object> PropertyValuesCache;
Timer SyncTimer;
public DynamicSyncProxy(T target, int intervalInMilliseconds = 1000)
{
Target = target;
Properties = Target.GetType().GetProperties()
.Where(p => !p.IsIndexer())
.ToDictionary(p => p.Name);
PropertyValuesCache = Properties.Values
.ToDictionary(p => p.Name, p => p.GetValue(Target));
SyncTimer = new Timer(o => SyncPropertyValues(), null, intervalInMilliseconds, intervalInMilliseconds);
}
public T GetTargetObject() => Target;
#region DynamicObject
public override IEnumerable<string> GetDynamicMemberNames()
{
return Properties.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = Properties[binder.Name].GetValue(Target);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Properties[binder.Name].SetValue(Target, value);
return true;
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#endregion
#region Sync
void SyncPropertyValues()
{
foreach (var name in Properties.Keys)
SyncPropertyValue(name);
}
void SyncPropertyValue(string propertyName)
{
var oldValue = PropertyValuesCache[propertyName];
var newValue = Properties[propertyName].GetValue(Target);
if (Equals(oldValue, newValue)) return;
PropertyValuesCache[propertyName] = newValue;
NotifyPropertyChanged(propertyName);
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment