From d3a0507f35c6951daa1cc06c4fe1c9f4e7664af5 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 14 Dec 2017 01:07:14 +0100 Subject: [PATCH] Implement custom observable for classes. Use a custom `ClassObserver` for observing changes to a control's classes. This saves shaves off about 15% memory use in ControlCatalog after cyling through all tabs. --- .../Styling/TypeNameAndClassSelector.cs | 70 ++++++++++++++++--- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs b/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs index fb32913e7e..5d48496e8c 100644 --- a/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs +++ b/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs @@ -5,9 +5,11 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Reactive; +using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reflection; using System.Text; +using Avalonia.Collections; namespace Avalonia.Styling { @@ -122,14 +124,7 @@ namespace Avalonia.Styling { if (subscribe) { - var observable = Observable.FromEventPattern< - NotifyCollectionChangedEventHandler, - NotifyCollectionChangedEventArgs>( - x => control.Classes.CollectionChanged += x, - x => control.Classes.CollectionChanged -= x) - .StartWith((EventPattern)null) - .Select(_ => Matches(control.Classes)) - .DistinctUntilChanged(); + var observable = new ClassObserver(control.Classes, _classes.Value); return new SelectorMatch(observable); } else @@ -204,5 +199,64 @@ namespace Avalonia.Styling return builder.ToString(); } + + private class ClassObserver : IObservable + { + readonly IList _match; + readonly List> _observers = new List>(); + IAvaloniaReadOnlyList _classes; + + public ClassObserver(IAvaloniaReadOnlyList classes, IList match) + { + _classes = classes; + _match = match; + } + + public IDisposable Subscribe(IObserver observer) + { + if (_observers.Count == 0) + { + _classes.CollectionChanged += ClassesChanged; + } + + _observers.Add(observer); + observer.OnNext(GetResult()); + + return Disposable.Create(() => + { + _observers.Remove(observer); + if (_observers.Count == 0) + { + _classes.CollectionChanged -= ClassesChanged; + } + }); + } + + private void ClassesChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.Action != NotifyCollectionChangedAction.Move) + { + foreach (var observer in _observers) + { + observer.OnNext(GetResult()); + } + } + } + + private bool GetResult() + { + int remaining = _match.Count; + + foreach (var c in _classes) + { + if (_match.Contains(c)) + { + --remaining; + } + } + + return remaining == 0; + } + } } }