protected override void BindProperty(object property) { boundProperty = property as IReadOnlyObservableCollection <T>; if (boundProperty == null) { boundProperty = BoxCollection(property); } if (boundProperty != null) { boundProperty.Reset += OnBoundPropertyReset; boundProperty.CountChanged += OnBoundPropertyCountChanged; boundProperty.ItemAdded += OnBoundPropertyItemAdded; boundProperty.ItemMoved += OnBoundPropertyItemMoved; boundProperty.ItemRemoved += OnBoundPropertyItemRemoved; boundProperty.ItemReplaced += OnBoundPropertyItemReplaced; exposedProperty.Clear(); foreach (var item in boundProperty) { exposedProperty.Add(item); } } else { Debug.LogError($"Property type ({property.GetType()}) cannot be bound as {typeof(IReadOnlyObservableCollection<T>)}", context); } }
/// <summary> /// Initializes a new instance of the <see cref="GroupingContainerList{TSource, TKey}"/> class. /// </summary> /// <param name="owner">The owner.</param> /// <param name="collection">The initial container collection.</param> /// <param name="keyComparer">The key comparer.</param> /// <param name="groups">The initial groups.</param> /// <exception cref="System.ArgumentException">At least one of the explicit groups is already in use.</exception> protected GroupingContainerList(IReadOnlyObservableCollection <ReadOnlyObservableGroup <TSource, TKey> > owner, IEnumerable <GroupedItemContainer <TSource, TKey> > collection, IEqualityComparer <TKey> keyComparer, IReadOnlyObservableCollection <ReadOnlyObservableGroup <TSource, TKey> > groups) : base(collection) { KeyComparer = keyComparer; Groups = groups; Owner = owner; foreach (var group in Groups) { if (group.Owner != null) { throw new ArgumentException("At least one of the explicit groups is already in use."); } group.Owner = Owner; } for (var i = 0; i < Items.Count; i++) { var container = Items[i]; container.SourceIndex = i; container.GroupIndex = -1; container.Group = null; container.ValueChanged += ContainerOnKeyChanged; } }
/// <summary> /// Initializes a new instance of the <see cref="SetDifferenceReadOnlyObservableCollection{T}"/> class. /// </summary> /// <param name="originalSource">The source collection.</param> /// <param name="substractedSource">The items to exclude from <paramref name="originalSource"/>.</param> /// <param name="comparer">The equality comparer.</param> public SetDifferenceReadOnlyObservableCollection(IReadOnlyObservableCollection <T> originalSource, IReadOnlyObservableCollection <T> substractedSource, IEqualityComparer <T> comparer = null) : base( originalSource, substractedSource, comparer ?? EqualityComparer <T> .Default, new ObservableSet <T>(new HashSet <T>(comparer))) { }
/// <summary> /// Observes propertychanges for items in the collection. /// </summary> /// <typeparam name="TProperty"></typeparam> /// <typeparam name="TItem">The type of the items in the collection</typeparam> /// <param name="source"></param> /// <param name="property">Sample: item => item.SomeProp.SomeNestedProp</param> /// <param name="signalInitial">When true a reset is singaled on subscribe.</param> /// <returns></returns> public static IObservable <EventPattern <ItemPropertyChangedEventArgs <TItem, TProperty> > > ObserveItemPropertyChanged <TItem, TProperty>( this IReadOnlyObservableCollection <TItem> source, Expression <Func <TItem, TProperty> > property, bool signalInitial = true) where TItem : class, INotifyPropertyChanged { return(new ItemsObservable <IReadOnlyObservableCollection <TItem>, TItem, TProperty>(source, property, signalInitial)); }
public static IDisposable connect_item_hooks <T>(IReadOnlyObservableCollection <T> source, Func <T, IDisposable> get_item_hook) { var item_hooks = source.Select(get_item_hook).ToList(); return(new CompositeDisposable( Disposable.wrap_collection(item_hooks), source.Subscribe((s, e) => CollectionHelper.reflect_change(item_hooks, source, get_item_hook, d => d.Dispose(), e)))); }
public static ReadOnlyFilteredView <T> AsReadOnlyFilteredView <T>( this IReadOnlyObservableCollection <T> collection, Func <T, bool> filter, params IObservable <object>[] triggers) { Ensure.NotNull(collection, nameof(collection)); return(new ReadOnlyFilteredView <T>(collection, filter, TimeSpan.Zero, null, triggers)); }
private DistinctReadOnlyObservableCollection(IReadOnlyObservableCollection <T> source, ObservableDictionary <T, int> containers) : base(containers.Keys) { _source = source; _containers = containers; AddRange(_containers, _source); CollectionChangedEventManager.AddListener(_source, this); }
/// <summary> /// Invokes an action for each item in a collection and subsequently each item added or /// removed from the collection. /// </summary> /// <typeparam name="T">The type of the collection items.</typeparam> /// <param name="collection">The collection.</param> /// <param name="added"> /// An action called initially for each item in the collection and subsequently for each /// item added to the collection. /// </param> /// <param name="removed"> /// An action called for each item removed from the collection. /// </param> /// <param name="reset"> /// An action called when the collection is reset. This will be followed by calls to /// <paramref name="added"/> for each item present in the collection after the reset. /// </param> /// <returns>A disposable used to terminate the subscription.</returns> public static IDisposable ForEachItem <T>( this IReadOnlyObservableCollection <T> collection, Action <T> added, Action <T> removed, Action reset) { Action <IList> add = items => { foreach (T item in items) { added(item); } }; Action <IList> remove = items => { for (var i = items.Count - 1; i >= 0; --i) { removed((T)items[i]); } }; NotifyCollectionChangedEventHandler handler = (_, e) => { switch (e.Action) { case NotifyCollectionChangedAction.Add: add(e.NewItems); break; case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Replace: remove(e.OldItems); add(e.NewItems); break; case NotifyCollectionChangedAction.Remove: remove(e.OldItems); break; case NotifyCollectionChangedAction.Reset: if (reset == null) { throw new InvalidOperationException( "Reset called on collection without reset handler."); } reset(); add((IList)collection); break; } }; add((IList)collection); collection.CollectionChanged += handler; return(new ActionDisposable(() => collection.CollectionChanged -= handler)); }
/// <summary> /// Initializes a new instance of the <see cref="ConditionalSwitchableCollectionSource{T}"/> class. /// </summary> /// <param name="condition">The condition.</param> /// <param name="positiveSource">The positive source.</param> /// <param name="negativeSource">The negative source.</param> public ConditionalSwitchableCollectionSource(IObservable <bool> condition, IReadOnlyObservableCollection <T> positiveSource, IReadOnlyObservableCollection <T> negativeSource) { _condition = condition ?? throw new ArgumentNullException(nameof(condition)); _positiveSource = positiveSource; _negativeSource = negativeSource; _subscription = condition.Subscribe(this); }
/// <summary> /// Initializes a new instance of the <see cref="SetDifferenceReadOnlyObservableList{T}"/> class. /// </summary> /// <param name="originalSource">The source collection.</param> /// <param name="substractedSource">The items to exclude from <paramref name="originalSource"/>.</param> /// <param name="comparer">The equality comparer.</param> public SetDifferenceReadOnlyObservableList(IReadOnlyObservableCollection <T> originalSource, IReadOnlyObservableCollection <T> substractedSource, IEqualityComparer <T> comparer = null) : this( originalSource, substractedSource, comparer ?? EqualityComparer <T> .Default, new ObservableDictionary <T, RefCountItemContainer <T> >( new Dictionary <T, RefCountItemContainer <T> >(comparer ?? EqualityComparer <T> .Default))) { }
/// <summary> /// Create a filtered view for <paramref name="source"/> /// </summary> /// <typeparam name="T">The type of the elements in the source collection.</typeparam> /// <param name="source">The source collection</param> /// <param name="filter">The predicate to filter by.</param> /// <param name="triggers">Triggers for when filtering is updated.</param> /// <returns>A <see cref="ReadOnlyFilteredView{T}"/></returns> public static ReadOnlyFilteredView <T> AsReadOnlyFilteredView <T>( this IReadOnlyObservableCollection <T> source, Func <T, bool> filter, params IObservable <object>[] triggers) { Ensure.NotNull(source, nameof(source)); Ensure.NotNull(filter, nameof(filter)); return(new ReadOnlyFilteredView <T>(source, filter, TimeSpan.Zero, null, false, triggers)); }
public static MappingView <TSource, TResult> AsMappingView <TSource, TResult>( this IReadOnlyObservableCollection <TSource> source, Func <TSource, int, TResult> selector, IScheduler scheduler) { Ensure.NotNull(source, nameof(source)); Ensure.NotNull(selector, nameof(selector)); return(new MappingView <TSource, TResult>(source, selector, scheduler, null)); }
public static MappingView <TSource, TResult> AsMappingView <TSource, TResult>( this IReadOnlyObservableCollection <TSource> source, Func <TSource, int, TResult> selector, params IObservable <object>[] triggers) { Ensure.NotNull(source, nameof(source)); Ensure.NotNull(selector, nameof(selector)); return(new MappingView <TSource, TResult>(source, selector, null, triggers)); }
private static void OnEventDaysPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { EventsView s = (EventsView)sender; IReadOnlyObservableCollection <EventDay> oldValue = (IReadOnlyObservableCollection <EventDay>)e.OldValue; IReadOnlyObservableCollection <EventDay> newValue = (IReadOnlyObservableCollection <EventDay>)e.NewValue; s.Unsubscribe(oldValue); s.Subscrube(newValue); s.UpdateViewEvents(newValue); }
/// <summary> /// Initializes a new instance of the <see cref="SortedReadOnlyObservableList{T}"/> class. /// </summary> /// <param name="source">The source collection.</param> /// <param name="comparison">The comparison used to establish the order of elements.</param> /// <param name="comparer"> /// A comparer for the list items. This is only used if the source collection is not a list /// and does not provide index information in its <see cref="NotifyCollectionChangedEventArgs"/> events. /// </param> /// <param name="triggers">The name of <typeparamref name="T"/>'s properties that can alter the collection's order.</param> public SortedReadOnlyObservableList(IReadOnlyObservableCollection <T> source, Comparison <T> comparison, IEqualityComparer <T> comparer, params string[] triggers) { _source = source; _eqComparer = new ContainerEqualityComparer <T, Container>(comparer); _items = new ContainerCollection(from item in source select new Container(item), new ContainerComparer(comparison), triggers); _items.SortedCollectionChanged += (sender, args) => RaiseEvents(args); CollectionChangedEventManager.AddListener(_source, this); }
/// <summary> /// Initializes a new instance of the <see cref="TransformingReadOnlyObservableList{TSource, TTarget}" /> class. /// </summary> /// <param name="source">The source collection.</param> /// <param name="selector">The transformation to apply to the items in <paramref name="source" />.</param> /// <param name="onRemove">The callback to execute when an item is removed from the collection.</param> /// <param name="targetComparer"> /// A comparer for the list items. This is only used if the source collection is not a list /// and does not provide index information in its <see cref="NotifyCollectionChangedEventArgs"/> events. /// </param> public TransformingReadOnlyObservableList(IReadOnlyObservableCollection <TSource> source, Func <TSource, TTarget> selector, Action <TTarget> onRemove = null, IEqualityComparer <TTarget> targetComparer = null) : base(new ObservableCollection <TTarget>(source.Select(selector))) { _source = source; _selector = selector; _onRemove = onRemove; _sourceComparer = targetComparer ?? EqualityComparer <TTarget> .Default; CollectionChangedEventManager.AddListener(source, this); }
public CollectionBoxer(IReadOnlyObservableCollection <TBoxed> boxedCollection) { this.boxedCollection = boxedCollection; boxedCollection.ItemAdded += BoxedCollectionItemAddedHandler; boxedCollection.CountChanged += BoxedCollectionCountChangedHandler; boxedCollection.ItemRemoved += BoxedCollectionItemRemovedHandler; boxedCollection.ItemMoved += BoxedCollectionItemMovedHandler; boxedCollection.ItemReplaced += BoxedCollectionItemReplacedHandler; boxedCollection.Reset += BoxedCollectionResetHandler; }
/// <summary> /// Observes propertychanges for items in the collection. /// </summary> /// <typeparam name="TItem">The type of the items in the collection</typeparam> /// <typeparam name="TProperty">The type of the property.</typeparam> /// <param name="source">The sopurce item to track changes for.</param> /// <param name="property">Sample: item => item.SomeProp.SomeNestedProp</param> /// <param name="signalInitial">When true a reset is singaled on subscribe.</param> public static IObservable <PropertyChangedEventArgs> ObserveItemPropertyChangedSlim <TItem, TProperty>( this IReadOnlyObservableCollection <TItem> source, Expression <Func <TItem, TProperty> > property, bool signalInitial = true) where TItem : class, INotifyPropertyChanged { Ensure.NotNull(source, nameof(source)); Ensure.NotNull(property, nameof(property)); return(ObserveItemPropertyChangedSlim <IReadOnlyObservableCollection <TItem>, TItem, TProperty>(source, property, signalInitial)); }
/// <summary> /// /// </summary> /// <typeparam name="TItem"></typeparam> /// <typeparam name="TValue"></typeparam> /// <param name="source"></param> /// <param name="selector"></param> /// <param name="whenEmpty"></param> /// <param name="trackItemChanges">If true we subscribe to property changes for each item. This is much slower.</param> /// <returns>A tracker with Value synced with source.Max()</returns> public static MaxTracker <TValue> TrackMax <TItem, TValue>(this IReadOnlyObservableCollection <TItem> source, Expression <Func <TItem, TValue> > selector, TValue?whenEmpty, bool trackItemChanges) where TItem : class, INotifyPropertyChanged where TValue : struct, IComparable <TValue> { var onItemChanged = trackItemChanges ? source.ObserveItemPropertyChanged(selector, false) : null; var mapped = source.AsMappingView(selector.Compile(), onItemChanged); return(new MaxTracker <TValue>(mapped, mapped.ObserveCollectionChangedSlim(false), whenEmpty)); }
/// <summary> /// Initializes a new instance of the <see cref="ContainsObservableResult{T}"/> class. /// </summary> /// <param name="source">The source.</param> /// <param name="value">The value to find.</param> /// <param name="comparer">The equality comparer. If it is <c>null</c> the default comparer is used.</param> /// <exception cref="System.ArgumentNullException">value</exception> public ContainsObservableResult(IReadOnlyObservableCollection <T> source, T value, IEqualityComparer <T> comparer = null) : base(source) { if (value == null) { throw new ArgumentNullException(nameof(value)); } Value = value; _comparer = comparer ?? EqualityComparer <T> .Default; CurrentValue = source.Contains(value, _comparer); }
public static ReadOnlyFilteredView <T> AsReadOnlyFilteredView <T>( this IReadOnlyObservableCollection <T> collection, Func <T, bool> filter, TimeSpan bufferTime, IScheduler scheduler, params IObservable <object>[] triggers) { Ensure.NotNull(collection, nameof(collection)); Ensure.NotNull(filter, nameof(filter)); Ensure.NotNull(scheduler, nameof(scheduler)); return(new ReadOnlyFilteredView <T>(collection, filter, bufferTime, scheduler, triggers)); }
public static MappingView <TSource, TResult> AsMappingView <TSource, TResult>( this IReadOnlyObservableCollection <TSource> source, Func <TSource, int, TResult> selector, Func <TResult, int, TResult> updater, IScheduler scheduler) where TSource : class where TResult : class { Ensure.NotNull(source, nameof(source)); Ensure.NotNull(selector, nameof(selector)); Ensure.NotNull(updater, nameof(updater)); return(new MappingView <TSource, TResult>(source, selector, updater, scheduler)); }
public NestedChanges(TCollection source, Expression <Func <TItem, TValue> > selector) { var path = NotifyingPath.GetOrCreate(selector); this.source = new MappingView <TItem, ValueTracker>( source: source, factory: Mapper.Create <TItem, ValueTracker>(x => new ValueTracker(this, x, path), x => x.Dispose()), bufferTime: TimeSpan.Zero, scheduler: null, leaveOpen: true); this.subscription = source.ObserveCollectionChangedSlim(signalInitial: false) .Subscribe(this.OnSourceChanged); }
public TrackingCollection( [CanBeNull] IReadOnlyObservableList <TFrom> sourceItems, [NotNull] Func <TFrom, TTo> createTargetItemFunc) { _sourceItems = sourceItems; _createTargetItemFunc = createTargetItemFunc ?? throw new ArgumentNullException(nameof(createTargetItemFunc)); _targetItemsWrapper = new ReadOnlyObservableCollectionWrapper <TTo, TTo>(_targetItems); if (sourceItems != null) { SetSource(sourceItems); } }
protected override void UnbindProperty() { if (boundProperty != null) { boundProperty.Reset -= OnBoundPropertyReset; boundProperty.CountChanged -= OnBoundPropertyCountChanged; boundProperty.ItemAdded -= OnBoundPropertyItemAdded; boundProperty.ItemMoved -= OnBoundPropertyItemMoved; boundProperty.ItemRemoved -= OnBoundPropertyItemRemoved; boundProperty.ItemReplaced -= OnBoundPropertyItemReplaced; boundProperty = null; } }
/// <summary> /// Initializes a new instance of the <see cref="FilteredReadOnlyObservableCollectionBase{TItem, TContainer}"/> class. /// </summary> /// <param name="items">The collection of item containers.</param> /// <param name="source">The source collection.</param> /// <param name="filter">The filter predicate.</param> /// <param name="itemComparer">The equality comparer for the items, in case <paramref name="source"/> is an index-less collection.</param> protected FilteredReadOnlyObservableCollectionBase(ObservableCollection <TContainer> items, IReadOnlyObservableCollection <TItem> source, Func <TItem, IObservable <bool> > filter, IEqualityComparer <TItem> itemComparer) { Source = source; Filter = filter; Items = items; ContainerComparer = new ContainerEqualityComparer <TItem, TContainer>(itemComparer); CollectionChangedEventManager.AddListener(Source, this); foreach (var item in source) { Items.Add(CreateContainer(item)); } }
private static IReadOnlyObservableCollection <T> BoxCollection(object collectionToBox) { IReadOnlyObservableCollection <T> result = null; Type collectionGenericType = collectionToBox.GetType().GetGenericTypeTowardsRoot(); if (collectionGenericType != null) { Type exposedType = typeof(T); Type boxedType = collectionGenericType.GenericTypeArguments[0]; Type activationType = typeof(CollectionBoxer <,>).MakeGenericType(exposedType, boxedType); result = Activator.CreateInstance(activationType, collectionToBox) as IReadOnlyObservableCollection <T>; } return(result); }
protected override NotifyCollectionChangedEventArgs BuildCompositeEventArgs(IReadOnlyObservableCollection <T> sender, NotifyCollectionChangedEventArgs e) { int GetSenderStartIndex() => ObservableCollections.TakeWhile(x => x != sender).Sum(x => x.Count); int GetNewItemsIndex() => GetSenderStartIndex() + (e.NewStartingIndex >= 0 ? e.NewStartingIndex : sender.Count); int GetOldItemsIndex() => GetSenderStartIndex() + (e.OldStartingIndex >= 0 ? e.OldStartingIndex : sender.IndexOf(x => EqualityComparer <T> .Default.Equals(x, (T)e.OldItems[0]))); switch (e.Action) { case NotifyCollectionChangedAction.Add: { return(CollectionChangedEventArgs.InsertRange(e.NewItems, GetNewItemsIndex())); } case NotifyCollectionChangedAction.Remove: { return(CollectionChangedEventArgs.RemoveRange(e.OldItems, GetOldItemsIndex())); } case NotifyCollectionChangedAction.Replace: { return(CollectionChangedEventArgs.ReplaceRange(e.OldItems, e.NewItems, GetOldItemsIndex())); } case NotifyCollectionChangedAction.Move: { return(null); } case NotifyCollectionChangedAction.Reset: { if (sender.Count == Count) { return(CollectionChangedEventArgs.Clear()); } return(CollectionChangedEventArgs.RemoveRange(sender.ToList(), GetSenderStartIndex())); } default: throw new NotSupportedException(); } }
/// <summary> /// Create a <see cref="ReadOnlyThrottledView{T}"/> view for <paramref name="source"/> /// </summary> /// <typeparam name="T">The type of the elements in the collection.</typeparam> /// <param name="source">The source collection</param> /// <param name="bufferTime">The time to buffer changes in <paramref name="source"/></param> /// <param name="scheduler">The scheduler to notify changes on.</param> /// <param name="leaveOpen">True means that the <paramref name="source"/> is not disposed when this instance is disposed.</param> /// <returns>A <see cref="ReadOnlyThrottledView{T}"/></returns> public static ReadOnlyThrottledView <T> AsReadOnlyThrottledView <T>(this IReadOnlyObservableCollection <T> source, TimeSpan bufferTime, IScheduler scheduler, bool leaveOpen = false) { return(new ReadOnlyThrottledView <T>(source, bufferTime, scheduler, leaveOpen)); }
public ReadOnlyThrottledView(IReadOnlyObservableCollection <T> collection, TimeSpan bufferTime, IScheduler scheduler) : this(bufferTime, scheduler, collection) { }