/// <summary> /// Exposes virtual protected for testing. /// </summary> /// <param name="oldValue">The old Value.</param> /// <param name="newValue">The new Value.</param> protected override void OnItemDefinitionPropertyChanged(TreeMapItemDefinition oldValue, TreeMapItemDefinition newValue) { base.OnItemDefinitionPropertyChanged(oldValue, newValue); if (OnItemDefinitionPropertyChangedEvent != null) { OnItemDefinitionPropertyChangedEvent(oldValue, newValue); } }
public virtual void ValueChildItemPadding() { TreeMapItemDefinition testItemDef = new TreeMapItemDefinition(); Assert.IsNotNull(testItemDef.ChildItemPadding); Assert.AreEqual(0, testItemDef.ChildItemPadding.Left); Assert.AreEqual(0, testItemDef.ChildItemPadding.Top); Assert.AreEqual(0, testItemDef.ChildItemPadding.Right); Assert.AreEqual(0, testItemDef.ChildItemPadding.Bottom); }
public virtual void ValuePathTest() { const string BindingName = "Foo"; TreeMapItemDefinition testItemDef = new TreeMapItemDefinition(); Assert.IsNull(testItemDef.ValueBinding); Assert.IsNull(testItemDef.ValuePath); testItemDef.ValuePath = BindingName; Assert.IsNotNull(testItemDef.ValueBinding); Assert.AreEqual(BindingName, testItemDef.ValueBinding.Path.Path); testItemDef.ValuePath = null; Assert.IsNull(testItemDef.ValueBinding); Assert.IsNull(testItemDef.ValuePath); }
/// <summary> /// Called when the value of the ItemDefinitionProperty property changes. /// </summary> /// <param name="d">Reference to the TreeMap object.</param> /// <param name="e">Event handler arguments.</param> private static void OnItemDefinitionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is TreeMap treeMap) { TreeMapItemDefinition oldValue = e.OldValue as TreeMapItemDefinition; TreeMapItemDefinition newValue = e.NewValue as TreeMapItemDefinition; // Unregister old TreeMapItemDefinition if (oldValue != null) { oldValue.PropertyChanged -= treeMap.OnItemDefinitionPropertyChanged; } // Register new TreeMapItemDefinition if (newValue != null) { newValue.PropertyChanged += treeMap.OnItemDefinitionPropertyChanged; } treeMap.OnItemDefinitionPropertyChanged(oldValue, newValue); } }
/// <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); }
/// <summary> /// Called when the value of the ItemDefinitionProperty property changes. /// Triggers a recalculation of the layout. /// </summary> /// <param name="oldValue">The old item definition.</param> /// <param name="newValue">The new item definition.</param> protected virtual void OnItemDefinitionPropertyChanged(TreeMapItemDefinition oldValue, TreeMapItemDefinition newValue) { RebuildTree(); }
public void TreeMapInheritViaProtectedVirtual() { InheritedTreeMap treeMap = new InheritedTreeMap(); // Set initial values. TreeMapItemDefinitionSelector selectorOld = new SampleTemplateSelector(); treeMap.SetValue(TreeMap.ItemDefinitionSelectorProperty, selectorOld); TreeMapItemDefinition definitionOld = new TreeMapItemDefinition { ChildItemPadding = new Thickness(0) }; treeMap.SetValue(TreeMap.ItemDefinitionProperty, definitionOld); int[] itemsOld = new int[] { 1 }; treeMap.SetValue(TreeMap.ItemsSourceProperty, itemsOld); Collection<Interpolator> collectionOld = new Collection<Interpolator> { new DoubleInterpolator() }; treeMap.SetValue(TreeMap.InterpolatorsProperty, collectionOld); // Test TreeMapItemDefinitionSelectorProperty TreeMapItemDefinitionSelector selectorNew = new SampleTemplateSelector(); bool calledItemDefinitionSelectorPropertyEvent = false; treeMap.OnItemDefinitionSelectorPropertyChangedEvent += (oldValue, newValue) => { Assert.AreEqual(oldValue, selectorOld); Assert.AreEqual(newValue, selectorNew); Assert.AreNotEqual(newValue, oldValue); Assert.IsFalse(calledItemDefinitionSelectorPropertyEvent); calledItemDefinitionSelectorPropertyEvent = true; }; treeMap.SetValue(TreeMap.ItemDefinitionSelectorProperty, selectorNew); Assert.IsTrue(calledItemDefinitionSelectorPropertyEvent); // Test ItemDefinitionProperty TreeMapItemDefinition definitionNew = new TreeMapItemDefinition { ChildItemPadding = new Thickness(1) }; bool calledItemDefinitionPropertyyEvent = false; treeMap.OnItemDefinitionPropertyChangedEvent += (oldValue, newValue) => { Assert.AreEqual(oldValue, definitionOld); Assert.AreEqual(newValue, definitionNew); Assert.AreNotEqual(newValue, oldValue); Assert.IsFalse(calledItemDefinitionPropertyyEvent); calledItemDefinitionPropertyyEvent = true; }; treeMap.SetValue(TreeMap.ItemDefinitionProperty, definitionNew); Assert.IsTrue(calledItemDefinitionPropertyyEvent); // Test ItemsSourceProperty int[] itemsNew = new int[] { 1, 2, 3 }; bool calledItemsSourceProperty = false; treeMap.OnItemsSourcePropertyChangedEvent += (oldValue, newValue) => { Assert.AreEqual(oldValue, itemsOld); Assert.AreEqual(newValue, itemsNew); Assert.AreNotEqual(newValue, oldValue); Assert.AreNotEqual(newValue, oldValue); Assert.IsFalse(calledItemsSourceProperty); calledItemsSourceProperty = true; }; treeMap.SetValue(TreeMap.ItemsSourceProperty, itemsNew); Assert.IsTrue(calledItemsSourceProperty); // Test InterpolatorsPropertyChanged Collection<Interpolator> collectionNew = new Collection<Interpolator> { new SolidColorBrushInterpolator() }; bool calledOnInterpolatorsPropertyChangedEvent = false; treeMap.OnInterpolatorsPropertyChangedEvent += (oldValue, newValue) => { Assert.AreEqual(oldValue, collectionOld); Assert.AreEqual(newValue, collectionNew); Assert.IsFalse(calledOnInterpolatorsPropertyChangedEvent); calledOnInterpolatorsPropertyChangedEvent = true; }; treeMap.SetValue(TreeMap.InterpolatorsProperty, collectionNew); Assert.IsTrue(calledOnInterpolatorsPropertyChangedEvent); }
public void ChangingContentsOfNestedObservableCollectionUpdatesTreeMap() { TreeMap treeMap = new TreeMap(); TreeMapItemDefinition itemDefinition = new TreeMapItemDefinition { ValueBinding = new Binding(), ItemsSource = new Binding("Value"), }; itemDefinition.ItemTemplate = (DataTemplate)XamlReader.Load(SimpleItemTemplate); treeMap.ItemDefinition = itemDefinition; ObservableCollection<int> nestedItemsSourceA = new ObservableCollection<int>(); ObservableCollection<int> nestedItemsSourceB = new ObservableCollection<int>(); treeMap.ItemsSource = new KeyValuePair<int, ObservableCollection<int>>[] { new KeyValuePair<int, ObservableCollection<int>>(0, nestedItemsSourceA), new KeyValuePair<int, ObservableCollection<int>>(0, nestedItemsSourceB), }; TestAsync( treeMap, // +1 because of the Border in default template () => Assert.AreEqual(0 + 2 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count()), () => nestedItemsSourceA.Add(1), () => Assert.AreEqual(1 + 2 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count()), () => nestedItemsSourceB.Add(2), () => Assert.AreEqual(2 + 2 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count()), () => nestedItemsSourceA.Add(3), () => Assert.AreEqual(3 + 2 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count()), () => nestedItemsSourceB.Clear(), () => Assert.AreEqual(2 + 2 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count()), () => nestedItemsSourceA.Clear(), () => Assert.AreEqual(0 + 2 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count())); }
public void ChangingTreeMapItemDefinitionItemsSourceUpdatesTreeMap() { TreeMap treeMap = new TreeMap(); TreeMapItemDefinition itemDefinition = new TreeMapItemDefinition { ValueBinding = new Binding() }; itemDefinition.ItemTemplate = (DataTemplate)XamlReader.Load(SimpleItemTemplate); treeMap.ItemDefinition = itemDefinition; treeMap.ItemsSource = new KeyValuePair<int, int[]>[] { new KeyValuePair<int, int[]>(1, new int[] { 2, 3, 4, 5 }) }; TestAsync( treeMap, // +1 because of the Border in default template () => Assert.AreEqual(1 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count()), () => itemDefinition.ItemsSource = new Binding("Value"), () => Assert.AreEqual(5 + 1, treeMap.GetVisualDescendents().OfType<Border>().Count())); }