Skip to content

Instantly share code, notes, and snippets.

@earthengine
Created November 4, 2016 04:19
Show Gist options
  • Save earthengine/80558baf30db613c4f50e9de5bfbdb11 to your computer and use it in GitHub Desktop.
Save earthengine/80558baf30db613c4f50e9de5bfbdb11 to your computer and use it in GitHub Desktop.
public static class EmptyHandlers
{
public static void EmptyHandler<T, U>(T s, U e) { }
}
public static class EntityExt
{
private static string PropertyFromMemberExpression(MemberExpression memberExpression)
{
var pinfo = memberExpression.Member as PropertyInfo;
if (pinfo != null)
{
return pinfo.Name;
}
var finfo = memberExpression.Member as FieldInfo;
if (finfo != null)
{
return finfo.Name;
}
return null;
}
/// <summary>
/// Usage
/// //Single property
/// PropertyNamesForExpression&lt;MyObject&gt;(x => x.MyProperty); // returns ["MyProperty"]
/// //Multiple properties
/// //PropertyNamesForExpression&lt;MyObject&gt;(x => new { x.MyProperty1, x.MyProperty2 }); // returns ["MyProperty1","MyProperty2"]
/// </summary>
/// <typeparam name="TObject">Type of objest with property of field</typeparam>
/// <param name="propertyExpression">Expression that access properties of a given object. Can be a simple property/field access or a
/// new anonymous class statement.</param>
/// <returns></returns>
public static IEnumerable<string> PropertyNamesFromExpression<TObject>(Expression<Func<TObject, object>> propertyExpression)
{
var lambda = propertyExpression as LambdaExpression;
var newexp = lambda.Body as NewExpression;
if (newexp == null)
{
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
if (memberExpression == null) yield break;
var result = PropertyFromMemberExpression(memberExpression);
if (result != null) yield return result;
yield break;
};
foreach (var arg in newexp.Arguments)
{
var memberExpression = arg as MemberExpression;
if (memberExpression == null) continue;
var result = PropertyFromMemberExpression(memberExpression);
if (result == null) continue;
yield return result;
}
}
/// <summary>
/// Add a handler for specific property changed event. Can specify a set of properties to be processed
/// </summary>
/// <typeparam name="TNotifier">The type of object that have properties changed</typeparam>
/// <param name="notifier">The object that have properties changed</param>
/// <param name="propertyExpression">
/// Property access expression, can be a single field/property access lambda,
/// or a lambda returns a new anonymous object that contains all properties interested
/// </param>
/// <param name="handler">The handler action</param>
public static void SubscribeToChanges<TNotifier>(this TNotifier notifier, Expression<Func<TNotifier, object>> propertyExpression,
Action<TNotifier> handler) where TNotifier : INotifyPropertyChanged
{
var propertyNames = PropertyNamesFromExpression(propertyExpression);
notifier.PropertyChanged +=
(s, e) =>
{
if (propertyNames.Contains(e.PropertyName) || string.IsNullOrEmpty(e.PropertyName))
{
handler(notifier);
}
};
}
/// <summary>
/// Given an action to raise the property changed event, iterate throw a set of properties, calls the action for each properties.
/// </summary>
/// <typeparam name="TNotifier">The type of object to notify</typeparam>
/// <param name="notifier"></param>
/// <param name="propertyExpression"></param>
/// <param name="notifyChangeDelegate"></param>
public static void RaisePropertiesChanged<TNotifier>(this TNotifier notifier, Expression<Func<TNotifier, object>> propertyExpression
, Action<string> notifyChangeDelegate)
{
foreach (var name in PropertyNamesFromExpression(propertyExpression))
{
notifyChangeDelegate(name);
}
}
public static void SetField<T>(this T obj, Action<T> exp, Expression<Func<T, object>> updatedProperties,
[CallerMemberName] string propertyName = null) where T : EntityBase
{
exp(obj);
if (propertyName != null)
obj.NotifyPropertyChanged(propertyName);
foreach (var fn in PropertyNamesFromExpression(updatedProperties))
{
obj.NotifyPropertyChanged(fn);
}
}
}
public abstract class EntityBase : INotifyPropertyChanged
{
protected static void NotifyPropertyChanged<T>(T t, Expression<Func<T, object>> func) where T : EntityBase
{
foreach (var fn in EntityExt.PropertyNamesFromExpression(func))
{
t.NotifyPropertyChanged(fn);
}
}
internal void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected void NotifyPropertyChanged<T>(Expression<Func<T, object>> exp)
{
foreach (var pn in EntityExt.PropertyNamesFromExpression(exp))
{
NotifyPropertyChanged(pn);
}
}
private PropertyChangedEventHandler propertyChanged = EmptyHandlers.EmptyHandler;
public event PropertyChangedEventHandler PropertyChanged
{
add { if (propertyChanged == EmptyHandlers.EmptyHandler) propertyChanged = value; else propertyChanged += value; }
remove { if (propertyChanged == value) propertyChanged = EmptyHandlers.EmptyHandler; else propertyChanged -= value; }
}
protected virtual bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
NotifyPropertyChanged(propertyName);
return true;
}
protected virtual void SetField(Action exp, [CallerMemberName] string propertyName = null)
{
exp();
NotifyPropertyChanged(propertyName);
}
protected void SetField<T>(Expression<Func<T>> get, T value, [CallerMemberName] string propertyName = null)
{
var m = get.Body as MemberExpression;
var tp = Expression.Variable(typeof(T), "t");
var m1 = Expression.PropertyOrField(m.Expression, m.Member.Name);
var setbody = Expression.Assign(m1, tp);
var set = Expression.Lambda<Action<T>>(setbody, tp);
SetField(set.Compile(), get.Compile(), value, propertyName);
}
private bool SetField<T>(Action<T> setter, Func<T> getter, T value, string propertyName)
{
var field = getter();
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
setter(value);
NotifyPropertyChanged(propertyName);
return true;
}
}
public class RelayCommand : ICommand
{
private EventHandler canExecuteChanged = EmptyHandlers.EmptyHandler;
private readonly Action _execute;
private readonly Func<bool> _canexecute;
public event EventHandler CanExecuteChanged
{
add { if (canExecuteChanged == EmptyHandlers.EmptyHandler) canExecuteChanged = value; else canExecuteChanged += value; }
remove { if (canExecuteChanged == value) canExecuteChanged = EmptyHandlers.EmptyHandler; else canExecuteChanged -= value; }
}
public RelayCommand(Action execute) : this(execute, () => true)
{
}
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
_execute = execute;
_canexecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canexecute();
}
public void Execute(object parameter)
{
_execute();
}
public void RaiseCanExecuteChanged()
{
canExecuteChanged(this, EventArgs.Empty);
}
}
public class RelayCommand<TParameter> : ICommand
{
private EventHandler canExecuteChanged = EmptyHandlers.EmptyHandler;
private readonly Action<TParameter> _execute;
private readonly Predicate<TParameter> _canexecute;
public event EventHandler CanExecuteChanged
{
add { if (canExecuteChanged == EmptyHandlers.EmptyHandler) canExecuteChanged = value; else canExecuteChanged += value; }
remove { if (canExecuteChanged == value) canExecuteChanged = EmptyHandlers.EmptyHandler; else canExecuteChanged -= value; }
}
public RelayCommand(Action<TParameter> execute) : this(execute, t => true)
{
}
public RelayCommand(Action<TParameter> execute, Predicate<TParameter> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
_execute = execute;
_canexecute = canExecute ?? (t => true);
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canexecute((TParameter)parameter);
}
public void Execute(object parameter)
{
_execute((TParameter)parameter);
}
public void RaiseCanExecuteChanged()
{
canExecuteChanged(this, EventArgs.Empty);
}
}
public class RoutedCommand : System.Windows.Input.RoutedCommand, ICommand
{
private EventHandler canExecuteChanged = EmptyHandlers.EmptyHandler;
public RoutedCommand(string name, Type ownerType) : base(name, ownerType)
{
base.CanExecuteChanged += canExecuteChanged;
}
public new event EventHandler CanExecuteChanged
{
add
{
base.CanExecuteChanged -= canExecuteChanged;
if (canExecuteChanged == EmptyHandlers.EmptyHandler)
{
canExecuteChanged = value;
}
else
{
canExecuteChanged += value;
}
base.CanExecuteChanged += canExecuteChanged;
}
remove
{
base.CanExecuteChanged -= canExecuteChanged;
if (canExecuteChanged == value)
{
canExecuteChanged = EmptyHandlers.EmptyHandler;
}
else
{
canExecuteChanged -= value;
}
base.CanExecuteChanged += canExecuteChanged;
}
}
public void RaiseCanExecuteChanged()
{
canExecuteChanged(this, EventArgs.Empty);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment