Exemplo n.º 1
0
        /// <summary>
        /// Registers a notification function for listening to changes to a tree of DependencyProperties relative to this DependencyObject instance.
        /// </summary>
        /// <param name="instance">The DependencyObject instance the dependency property tree starts at.</param>
        /// <param name="callback">A callback based on the PropertyChangedCallback delegate, which the system invokes when the value of any of the specified properties changes.</param>
        /// <param name="properties">The tree of dependency property to register for property-changed notification.</param>
        /// <returns>A disposable that will unregister the callback when disposed.</returns>
        /// <remarks>
        /// <para>Each node of the dependency property tree is represented by an array describing the path of the dependency property relative to the given dependency object instance.</para>
        /// <para>For example, to register for notifications to changes to the Color of a TextBlock's Foreground:</para>
        /// <code>var disposable = myTextBlock.RegisterDisposableNestedPropertyChangedCallback(callback, new [] { TextBlock.ForegroundProperty, SolidColorBrush.ColorProperty });</code>
        /// </remarks>
        internal static IDisposable RegisterDisposableNestedPropertyChangedCallback(this DependencyObject instance, PropertyChangedCallback callback, params DependencyProperty[][] properties)
        {
            if (instance == null)
            {
                return(Disposable.Empty);
            }

            return(properties
                   .Where(Enumerable.Any)
                   .GroupBy(Enumerable.First, propertyPath => propertyPath.Skip(1).ToArray())
                   .Where(Enumerable.Any)
                   .Where(group => group.Key != null)
                   .Select(group =>
            {
                var property = group.Key;
                var subProperties = group.ToArray();

                // Validate the property owner type
                if (!instance.GetType().Is(property.OwnerType) && !property.IsAttached)
                {
                    return Disposable.Empty;
                }

                var childDisposable = new SerialDisposable();

                childDisposable.Disposable = (instance.GetValue(property) as DependencyObject)?.RegisterDisposableNestedPropertyChangedCallback(callback, subProperties);

                var disposable = instance.RegisterDisposablePropertyChangedCallback(property, (s, e) =>
                {
                    callback(s, e);

                    childDisposable.Disposable = s?.RegisterDisposableNestedPropertyChangedCallback(callback, subProperties);
                });

                return new CompositeDisposable(disposable, childDisposable);
            })
                   .Apply(disposables => new CompositeDisposable(disposables)));
        }