Esempio n. 1
0
        internal static void AddChild(TreeViewItemViewModel parent, ModelItem item, object value, bool duplicatedNodeVisible, string childNodePrefix, ModelProperty trackingProperty)
        {
            // If necessary, evaluate uniqueness of given item
            bool isUnique = false;

            if (!duplicatedNodeVisible)
            {
                // Note: These evaluations expect item to be an immediate child of trackingProperty.Value
                // Intermediate nodes would for example undermine simple check just below
                //
                // Caveat 1: Aim is to greatly reduce, not to eliminate, display of nodes visible elsewhere
                // Caveat 1a: Nodes reachable from other isolated nodes are included in the collection
                // Caveat 1b: Nodes that are not isolated may be reachable from isolated nodes and thus
                // displayed together with the isolated ones; ShowPropertyInOutlineViewAsSiblingAttribute may make this seem normal
                // (If complete duplicate elimination were the aim, would likely need a "never expand"
                // display mode for duplicateNodeVisible=false children)
                // Caveat 2: Use of single uniqueChildren field may cause all children of a second
                // duplcatedNodeVisible=false property to be ignored if (fortunately only if) neither
                // property uses ShowPropertyInOutlineViewAttribute(true) -- that attribute's default
                // Caveat 3-n: Please see caveats described at top of UniqueModelItemHelper
                if (1 >= item.Parents.Count())
                {
                    isUnique = true;
                }
                else
                {
                    // Avoided a thorough evaluation as long as we can
                    if (null == parent.uniqueChildren)
                    {
                        parent.uniqueChildren = UniqueModelItemHelper.FindUniqueChildren(trackingProperty);
                    }

                    isUnique = parent.uniqueChildren.Contains(item);
                }
            }

            // If displayable now, create the view model node
            if (duplicatedNodeVisible || isUnique)
            {
                TreeViewItemViewModel child = TreeViewItemViewModel.CreateViewModel(parent, value);
                child.NodePrefixText = childNodePrefix;
                parent.AddChild(child, trackingProperty);
            }
            // Track for potential addition or removal of parents even if not presently visible
            if (!duplicatedNodeVisible)
            {
                ModelItemImpl itemImpl = item as ModelItemImpl;
                if (null != itemImpl)
                {
                    ChangeNotificationTracker tracker = parent.GetTracker(trackingProperty);
                    tracker.AddCollection(itemImpl.InternalParents);
                    tracker.AddCollection(itemImpl.InternalSources);
                }
            }
        }
        // Return HashSet containing ModelItems found only through given property: Cannot reach property.Parent without
        // hitting property from these immediate descendents of property.Value
        // Set may contain some internal duplication -- all nodes, not just the root, of a linked tree will be included
        //
        // Caveat 1: Due to problems removing Parents (e.g. Case content sometimes holds references to FlowSwitch after
        // Case removed), this method is not entirely reliable -- customers may occasionally need to reopen Designer
        // Caveat 2: Due to lazy loading of Properties (and therefore the back-pointing Parents collection), may
        // temporarily include non-unique ModelItems in returned set -- cleared as tree or designer views expand
        //
        // (Throughout, cannot use ModelItem.GetParentEnumerator because that does not check all Sources and Parents)
        internal static HashSet <ModelItem> FindUniqueChildren(ModelProperty property)
        {
            HashSet <ModelItem> retval = new HashSet <ModelItem>();

            if (null != property && null != property.Parent && null != property.Value)
            {
                ModelItem           target   = property.Parent;
                ModelItem           expected = property.Value;
                HashSet <ModelItem> visited  = new HashSet <ModelItem>();

                // Check all immediate children of property.Value
                ModelItemCollection collection = expected as ModelItemCollection;
                if (null == collection)
                {
                    ModelItemDictionary dictionary = expected as ModelItemDictionary;
                    if (null == dictionary)
                    {
                        // ModelItem
                        // Can't use UniqueRoute because we're starting at expected
                        // Can't use EnqueueParents because we need to special-case given property
                        // Instead confirm property.Value is not referenced anywhere else
                        ModelItemImpl expectedImpl = expected as ModelItemImpl;
                        if (null != expectedImpl)
                        {
                            bool justThisSource = true;

                            // expectedImpl.InternalParents does not include ModelItems that are just Sources
                            if (0 == expectedImpl.InternalParents.Count)
                            {
                                // expectedImpl.InternalSources would be similar but adds a wrapper we don't need here
                                foreach (ModelProperty source in expected.Sources)
                                {
                                    if (null != source.Parent && !visited.Contains(source.Parent))
                                    {
                                        visited.Add(source.Parent);
                                        if (!property.Equals(source) && !expected.Equals(source) &&
                                            null == ExtensibilityAccessor.GetAttribute <HidePropertyInOutlineViewAttribute>(source))
                                        {
                                            // Found a non-ignored property from somewhere else referencing expected
                                            justThisSource = false;
                                            break;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // Found a Parent that's not a Source.Parent: property.Value is in some collection
                                justThisSource = false;
                            }

                            if (justThisSource)
                            {
                                retval.Add(expected);
                            }
                        }
                    }
                    else
                    {
                        // ModelItemDictionary
                        foreach (KeyValuePair <ModelItem, ModelItem> child in dictionary)
                        {
                            if (null != child.Key && !visited.Contains(child.Key))
                            {
                                visited.Add(child.Key);
                                if (UniqueModelItemHelper.UniqueRoute(child.Key, target, expected))
                                {
                                    retval.Add(child.Key);
                                }
                            }

                            if (null != child.Value && !visited.Contains(child.Value))
                            {
                                visited.Add(child.Value);
                                if (UniqueModelItemHelper.UniqueRoute(child.Value, target, expected))
                                {
                                    retval.Add(child.Value);
                                }
                            }
                        }
                    }
                }
                else
                {
                    // ModelItemCollection
                    foreach (ModelItem child in collection)
                    {
                        if (null != child && !visited.Contains(child))
                        {
                            visited.Add(child);
                            if (UniqueModelItemHelper.UniqueRoute(child, target, expected))
                            {
                                retval.Add(child);
                            }
                        }
                    }
                }
            }

            return(retval);
        }