/// <summary> /// Callback executed when an item's property gets updated /// </summary> /// <param name="sender"> /// Items /// </param> /// <param name="e"> /// Argument containing the name of the property that raised the changes /// </param> private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e) { // lots of properties gets updated, we watch only those which belongs to visible fieldnames // and those who were registered for propertychanges monitoring // and of course if the item is still on the list if (_valueGetters.Any(vg => vg.FieldName == e.PropertyName)) { PropertyFilterValueGetter pf = _valueGetters.FirstOrDefault(vg => vg.FieldName == e.PropertyName); if (pf.MonitorPropertyChanged && _substituteSource.Contains(sender)) { // To avoid doing a refresh on a property change which would end in a very hawful user experience // we simulate a replace to the collection because the filter is automatically applied in this case int index = _substituteSource.IndexOf(sender); var argsReplace = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, new List <object> { sender }, new List <object> { sender }, index); _substituteSource.RaiseCollectionChanged(argsReplace); } NotifyResults(); // Notify results } }
/// <summary> /// Method called when FilterColumns property changes /// </summary> /// <exception cref="InvalidOperationException"> /// Raised when a a property filter refers to a non existing candidate object type property /// </exception> private void SetFilterColumns() { var propertyFilters = Items.Cast<ValueFilter>().ToList(); if (UnderlyingType.Equals(typeof (string)) || UnderlyingType.IsValueType) { // for native types, only one ValueFilter accepted to apply string format or IValueConverter if (propertyFilters.Count > 1) { throw new InvalidOperationException( "Only one property filter is authorized when underlying type is String or a value type."); } // Then if there is no property filter at all, there is no conversion needed and we build a defautl property getter // and there is one, we build a property getter accordingly _valueGetters.Add(propertyFilters.Count == 0 ? new PropertyFilterValueGetter(new ValueFilter()) : new PropertyFilterValueGetter(propertyFilters[0])); } // if the underlying type if neither a string nor value type, then it is a reference type else { IEnumerable<PropertyFilter> apfs; // if there is no PropertyFilter defined, we build it by default based on every instance public properties of the underlying type if (propertyFilters.Count == 0) { apfs = new List<PropertyFilter>(); // Get the type Properties var pis = UnderlyingType.GetProperties(BindingFlags.Public | BindingFlags.Instance); // iterate foreach (var propertyInfo in pis) { var pf = new PropertyFilter(propertyInfo.Name, DefaultMonitorPropertyChanges); var pfvg = new PropertyFilterValueGetter(pf, UnderlyingType); // Generate... _valueGetters.Add(pfvg); // ...and add value getter for each properties } } else { // and thus every ValueFilter must be PropertyFilter if (propertyFilters.Any(p => !(p is PropertyFilter))) { throw new InvalidOperationException("ValueFilter can't be used with reference type."); } apfs = propertyFilters.Cast<PropertyFilter>().ToList(); foreach (PropertyFilter pf in apfs) { // Get the PropertyInfo PropertyInfo pi = UnderlyingType.GetProperty(pf.FieldName); // this info is mandatory if (pi == null) { throw new InvalidOperationException( string.Format("Cant't find the property {0} for type {1}", pf.FieldName, UnderlyingType.Name)); } // If pi is ok, build the value getter and add it to the list var pfvg = new PropertyFilterValueGetter(pf, UnderlyingType); _valueGetters.Add(pfvg); } } // If there is no ValueFilter which is set to be monitored for property changes, we keep track of it to avoid to subscribe to propertychanged event later on _hasAnyPropertyChangesToMonitor = apfs.Any(p => p.MonitorPropertyChanged); } }
/// <summary> /// Method called when FilterColumns property changes /// </summary> /// <exception cref="InvalidOperationException"> /// Raised when a a property filter refers to a non existing candidate object type property /// </exception> private void SetFilterColumns() { var propertyFilters = Items.Cast <ValueFilter>().ToList(); if (UnderlyingType.Equals(typeof(string)) || UnderlyingType.IsValueType) { // for native types, only one ValueFilter accepted to apply string format or IValueConverter if (propertyFilters.Count > 1) { throw new InvalidOperationException( "Only one property filter is authorized when underlying type is String or a value type."); } // Then if there is no property filter at all, there is no conversion needed and we build a defautl property getter // and there is one, we build a property getter accordingly _valueGetters.Add(propertyFilters.Count == 0 ? new PropertyFilterValueGetter(new ValueFilter()) : new PropertyFilterValueGetter(propertyFilters[0])); } // if the underlying type if neither a string nor value type, then it is a reference type else { IEnumerable <PropertyFilter> apfs; // if there is no PropertyFilter defined, we build it by default based on every instance public properties of the underlying type if (propertyFilters.Count == 0) { apfs = new List <PropertyFilter>(); // Get the type Properties var pis = UnderlyingType.GetProperties(BindingFlags.Public | BindingFlags.Instance); // iterate foreach (var propertyInfo in pis) { var pf = new PropertyFilter(propertyInfo.Name, DefaultMonitorPropertyChanges); var pfvg = new PropertyFilterValueGetter(pf, UnderlyingType); // Generate... _valueGetters.Add(pfvg); // ...and add value getter for each properties } } else { // and thus every ValueFilter must be PropertyFilter if (propertyFilters.Any(p => !(p is PropertyFilter))) { throw new InvalidOperationException("ValueFilter can't be used with reference type."); } apfs = propertyFilters.Cast <PropertyFilter>().ToList(); foreach (PropertyFilter pf in apfs) { // Get the PropertyInfo PropertyInfo pi = UnderlyingType.GetProperty(pf.FieldName); // this info is mandatory if (pi == null) { throw new InvalidOperationException( string.Format("Cant't find the property {0} for type {1}", pf.FieldName, UnderlyingType.Name)); } // If pi is ok, build the value getter and add it to the list var pfvg = new PropertyFilterValueGetter(pf, UnderlyingType); _valueGetters.Add(pfvg); } } // If there is no ValueFilter which is set to be monitored for property changes, we keep track of it to avoid to subscribe to propertychanged event later on _hasAnyPropertyChangesToMonitor = apfs.Any(p => p.MonitorPropertyChanged); } }