/// <summary> /// All steps in the path must implement INotifyPropertyChanged, this throws if this condition is not met. /// </summary> /// <param name="path"> /// </param> private static void VerifyPath(IPropertyPath path) { for (int i = 0; i < path.Count - 1; i++) { var propertyInfo = path[i].PropertyInfo; if (propertyInfo.PropertyType.IsValueType) { var message = string.Format( "Property path cannot have structs in it. Copy by value will make subscribing error prone. Also mutable struct much?" + Environment.NewLine + "The type {0} is a value type not so {1}.{2} will not notify when it changes." + Environment.NewLine + "The path is: {3}", propertyInfo.PropertyType.PrettyName(), i == 0 ? "x" : path[i - 1].PropertyInfo.Name, propertyInfo.Name, path); throw new ArgumentException(message, nameof(path)); } if (!typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType)) { var message = string.Format( "All levels in the path must implement INotifyPropertyChanged." + Environment.NewLine + "The type {0} does not so {1}.{2} will not notify when it changes." + Environment.NewLine + "The path is: {3}", propertyInfo.PropertyType.PrettyName(), i == 0 ? "x" : path[i - 1].PropertyInfo.Name, propertyInfo.Name, path); throw new ArgumentException(message, nameof(path)); } } }
/// <summary> /// Retrieve property path info. /// Throw error if unavailable. /// This only examines public instance properties. /// </summary> /// <param name="t"></param> /// <param name="propertyPathString"></param> /// <param name="cacheProvider"></param> /// <returns></returns> private static IPropertyPath GetPropertyPath(Type t, String propertyPathString, ICacheService cacheProvider) { String cacheKey = null; IPropertyPath propertyPath = null; if (cacheProvider != null) { cacheKey = t.FullName + "#" + propertyPathString; propertyPath = cacheProvider[cacheKey] as IPropertyPath; } if (propertyPath == null) { if (propertyPathString.IndexOf('.') > -1) { propertyPath = new ComplexPropertyPath(t, propertyPathString); } else { propertyPath = new SimplePropertyPath(t, propertyPathString); } if (cacheProvider != null) { cacheProvider[cacheKey] = propertyPath; } } return(propertyPath); }
/// <summary> /// Retrieve a property value. /// </summary> /// <param name="instance"></param> /// <param name="propertyPathString">Path to property to set, separated by periods if setting a subproperty (Account.Address.City)</param> /// <param name="cacheProvider">Used to cache the propertyinfo information. May be null to skip cache.</param> /// <returns></returns> /// <exception cref="KeyNotFoundException">Property can't be found</exception> public static object GetPropertyValue(object instance, String propertyPathString, ICacheService cacheProvider) { IPropertyPath propertyPath = GetPropertyPath(instance.GetType(), propertyPathString, cacheProvider); PropertyInfo propInfo; propertyPath.FollowPropertyPath(instance, out instance, out propInfo); if (instance == null) { return(null); } return(propInfo.GetValue(instance, null)); }
/// <summary> /// Inicjalizuje wiązanie. /// </summary> /// <param name="source">Obiekt źródłowy.</param> /// <param name="sourceProperty">Ścieżka do źródła.</param> /// <param name="target">Obiekt docelowy.</param> /// <param name="targetProperty">Ścieżka do celu.</param> /// <param name="mode">Tryb wiązania.</param> /// <param name="converterType">Wymuszony typ konwertera.</param> /// <exception cref="ArgumentNullException">Któryś z argumentów jest nullem.</exception> internal Binding(object source, IPropertyPath sourceProperty, object target, IPropertyPath targetProperty, bool setTarget, BindingMode mode = BindingMode.OneWay, Type converterType = null) { if (source == null) { throw new ArgumentNullException("source"); } if (sourceProperty == null) { throw new ArgumentNullException("sourceProperty"); } if (target == null) { throw new ArgumentNullException("target"); } if (targetProperty == null) { throw new ArgumentNullException("targetProperty"); } this.SourcePath = sourceProperty; if (!this.SourcePath.Initialized) { this.SourcePath.BeginInit(); this.SourcePath.Root = source; this.SourcePath.EndInit(); } else { this.SourcePath.Root = source; } this.TargetPath = targetProperty; if (!this.TargetPath.Initialized) { this.TargetPath.BeginInit(); this.TargetPath.Root = target; this.TargetPath.EndInit(); } else { this.TargetPath.Root = target; } this.Mode = mode; this.ConverterType = converterType; this.SetBindings(); if (setTarget) { this.TargetPath.Value = this.GetConvertedSource(); } }
/// <summary> /// Set a value on the specified object. /// If the specified property is not found then this call will be ignored. /// </summary> /// <param name="instance">Instance the value will be set on</param> /// <param name="propertyPathString">Path to property. Subproperties may be separated by periods (Account.Address.City).</param> /// <param name="value">Value to be set</param> /// <param name="cacheProvider">Used to cache the propertyinfo information. May be null to skip cache.</param> public static void SetPropertyValue(object instance, String propertyPathString, object value, ICacheService cacheProvider) { IPropertyPath propertyPath = GetPropertyPath(instance.GetType(), propertyPathString, cacheProvider); PropertyInfo propInfo; propertyPath.FollowPropertyPath(instance, out instance, out propInfo); //if (propInfo == null) // throw new KeyNotFoundException("Property " + propertyPathString + " can't be located on " + instance.GetType().FullName); if (value != null && !propInfo.ReflectedType.IsAssignableFrom(value.GetType())) { value = BuildObjectValue(value, propInfo.PropertyType, propertyPathString); } propInfo.SetValue(instance, value, null); }
internal NotifyingPath(RootItem root, IPropertyPath path) { this.root = root; var items = new INotifyingPathItem[path.Count + 1]; items[0] = root; INotifyingPathItem previous = root; for (int i = 0; i < path.Count; i++) { var item = new NotifyingPathItem(previous, path[i]); items[i + 1] = item; previous = item; } this.parts = items; }
public void SetUp() { this.Data = new Data1(); this.Data.Data = new Data2(); this.Data.Data.Items = new Data3[] { new Data3{Value = 0}, new Data3{Value = 1}, new Data3{Value = 2}, new Data3{Value = 3} }; this.Path = new PropertyPath("Data.Data[1].Value", typeof(PropertyPathTests)); this.Path.BeginInit(); this.Path.Root = this; this.Path.EndInit(); }
public static T Property <T>(this T targetPropertyPath, IPropertyPath value) where T : ITargetPropertyPath { targetPropertyPath.Property = value; return(targetPropertyPath); }
/// <summary> /// Inicjalizuje wiązanie. /// </summary> /// <param name="source">Obiekt źródłowy.</param> /// <param name="sourceProperty">Ścieżka do źródła.</param> /// <param name="target">Obiekt docelowy.</param> /// <param name="targetProperty">Ścieżka do celu.</param> /// <param name="mode">Tryb wiązania.</param> /// <param name="converterType">Wymuszony typ konwertera.</param> /// <exception cref="ArgumentNullException">Któryś z argumentów jest nullem.</exception> public Binding(object source, IPropertyPath sourceProperty, object target, IPropertyPath targetProperty, BindingMode mode = BindingMode.OneWay, Type converterType = null) : this(source, sourceProperty, target, targetProperty, true, mode, converterType) { }