/// <summary> /// If the DataRangeBinding property is set then this method updates the minimum/maximum range /// of this object by including the value passed in. /// </summary> /// <param name="data">Object to extract the value from (the Source of the DataRangeBinding).</param> internal virtual void IncludeInRange(object data) { if (DataRangeBinding != null) { if (!Double.IsNaN(DataMinimum) && !Double.IsNaN(DataMaximum)) { return; } IConvertible input = _helper.RetrieveProperty(data, DataRangeBinding) as IConvertible; if (input == null) { throw new ArgumentException( Properties.Resources.Interpolator_IncludeInRange_DataRangeBindingNotIConvertible); } double value = input.ToDouble(CultureInfo.InvariantCulture); if (Double.IsNaN(DataMinimum) && value < ActualDataMinimum) { ActualDataMinimum = value; } if (Double.IsNaN(DataMaximum) && value > ActualDataMaximum) { ActualDataMaximum = value; } } }
/// <summary> /// Builds the parallel trees of TreeMapNodes with references to the original user's trees. /// </summary> /// <param name="nodes">The list of roots of the user hierarchies (whatever was passed through ItemsSource).</param> /// <param name="level">Level being processed at this recursive call (the root node is at level 0).</param> /// <returns>The list of roots of the internal trees of TreeMapNodes.</returns> private IEnumerable <TreeMapNode> BuildTreeMapTree(IEnumerable nodes, int level) { List <TreeMapNode> retList = new List <TreeMapNode>(); if (nodes == null) { return(retList); } foreach (object root in nodes) { // Give the template selector a chance to override the template for this item. TreeMapItemDefinition template = null; if (ItemDefinitionSelector != null) { template = ItemDefinitionSelector.SelectItemDefinition(this, root, level); } // Use the default otherwise if (template == null) { template = ItemDefinition; } if (template == null) { throw new ArgumentException( Properties.Resources.TreeMap_BuildTreeMapTree_TemplateNotSet); } // Silently create 0 elements if ValueBinding is set to null // in the template if (template.ValueBinding != null) { IEnumerable objectChildren = (template.ItemsSource != null) ? _helper.RetrieveProperty(root, template.ItemsSource) as IEnumerable : null; IEnumerable <TreeMapNode> children = (objectChildren != null) ? BuildTreeMapTree(objectChildren, level + 1) : children = Enumerable.Empty <TreeMapNode>(); // Subscribe to CollectionChanged for the collection WeakEventListener <TreeMap, object, NotifyCollectionChangedEventArgs> weakEventListener = null; INotifyCollectionChanged objectChildrenINotifyCollectionChanged = objectChildren as INotifyCollectionChanged; if (objectChildrenINotifyCollectionChanged != null) { // Use a WeakEventListener so that the backwards reference doesn't keep this object alive weakEventListener = new WeakEventListener <TreeMap, object, NotifyCollectionChangedEventArgs>(this); weakEventListener.OnEventAction = (instance, source, eventArgs) => instance.ItemsSourceCollectionChanged(source, eventArgs); weakEventListener.OnDetachAction = (wel) => objectChildrenINotifyCollectionChanged.CollectionChanged -= wel.OnEvent; objectChildrenINotifyCollectionChanged.CollectionChanged += weakEventListener.OnEvent; } // Auto-aggregate children area values double area; if (children.Any()) { area = children.Sum(x => x.Area); } else { IConvertible value = _helper.RetrieveProperty(root, template.ValueBinding) as IConvertible; if (value == null) { // Provide a default value so there's something to display value = 1.0; } area = value.ToDouble(CultureInfo.InvariantCulture); } // Do not include elements with negative or 0 size in the // VisualTransition tree. We skip interpolation for such // elements as well if (area > 0) { // Calculate ranges for all interpolators, only consider leaf // nodes in the LeafNodesOnly mode, or all nodes in the AllNodes // mode. foreach (Interpolator interpolator in Interpolators) { if (interpolator.InterpolationMode == InterpolationMode.AllNodes || !children.Any()) { interpolator.IncludeInRange(root); } } retList.Add(new TreeMapNode() { DataContext = root, Level = level, Area = area, ItemDefinition = template, ChildItemPadding = template.ChildItemPadding, Children = children, WeakEventListener = weakEventListener, }); } } } return(retList); }