// Tries to figure out what property to select and selects is
        private void UpdateSelectedProperty(View.Selection selection)
        {

            // If we are not loaded, skip any and all selection magic
            if (!this.IsLoaded)
            {
                return;
            }

            if (selection != null)
            {

                // See what the view would like us to select if we run out of things
                // we can think of selecting
                //
                SelectionPath fallbackSelection = null;
                if (_propertyToolBar.CurrentViewManager != null)
                {
                    fallbackSelection = _propertyToolBar.CurrentViewManager.GetDefaultSelectionPath(_categoryList);
                }

                // Select the first thing we request that exists, using the following
                // precedence order:
                //
                //  * LastSelectionPath
                //  * DefaultProperty
                //  * Whatever the view wants to show (first category, first property, ...)
                //
                _categoryList.UpdateSelectedProperty(
                    this.LastSelectionPath,
                    ModelPropertyMerger.GetMergedDefaultProperty(selection.SelectedObjects),
                    fallbackSelection);
            }

            if (DesignerPerfEventProvider != null)
            {
                DesignerPerfEventProvider.PropertyInspectorUpdatePropertyListEnd();
            }
        }
        // This is the work-horse that refreshes the list of properties and categories within a PropertyInspector
        // window, including refreshing of CategoryEditors, based on the specified selection
        private void UpdateCategories(View.Selection selection, bool attachedOnly)
        {

            // Optimization stolen from Sparkle:
            // re-rendering the categories is the number one perf issue. Clearing
            // the databound collection results in massive Avalon code execution, and
            // then re-adding everything causes another huge shuffle. What is more, 
            // even when changing the selection between different objects, most properties
            // do not change. Therefore we are going to take the new list of properties 
            // and we are going to merge them into the existing stuff, using an 
            // approach I call Mark, Match, and Cull.
            //
            // First we mark all the properties in the current collection. Those which 
            // are still marked at the end will be culled out
            foreach (ModelCategoryEntry category in _categoryList)
            {
                if (attachedOnly)
                {
                    category.MarkAttachedPropertiesDisassociated();
                }
                else
                {
                    category.MarkAllPropertiesDisassociated();
                }
            }

            // Second we try to match each property in the list of properties for the newly selected objects 
            // against something that we already have. If we have a match, then we reset the existing
            // ModelPropertyEntry and clear the mark
            //
            foreach (IEnumerable<ModelProperty> propertySet in
                ModelPropertyMerger.GetMergedProperties(
                selection == null ? null : selection.SelectedObjects,
                selection == null ? 0 : selection.SelectionCount))
            {

                string propertyName = GetPropertyName(propertySet);

                // Specifically filter out the Name property
                // PS 40699 - Name is not a special property for WF
                //if ("Name".Equals(propertyName))
                //{
                //    continue;
                //}

                if (attachedOnly && propertyName.IndexOf('.') < 0)
                {
                    continue;
                }

                ModelPropertyEntry wrappedProperty = _propertyToolBar.CurrentViewManager.AddProperty(propertySet, propertyName, _categoryList);

                // Make sure no valid properties get culled out
                wrappedProperty.Disassociated = false;
            }

            // Third, we walk the properties and categories, and we cull out all of the
            // marked properties. Empty categories are removed.
            //
            for (int i = _categoryList.Count - 1; i >= 0; i--)
            {
                ModelCategoryEntry category = (ModelCategoryEntry)_categoryList[i];
                category.CullDisassociatedProperties();
                if (category.IsEmpty)
                {
                    _categoryList.RemoveAt(i);
                }
            }

            _categoryList.RefreshFilter();
        }
        // Helper method that adjusts the visible set of CategoryEditors based on the specified selection
        private void UpdateCategoryEditors(View.Selection selection)
        {

            // Figure out which category editors to show
            Dictionary<Type, object> newCategoryEditorTypes = _propertyToolBar.CurrentViewManager.GetCategoryEditors(
                FindCommonType(selection == null ? null : selection.SelectedObjects),
                _categoryList);

            // Figure out which CategoryEditors are no longer needed and remove them
            List<Type> editorTypesToRemove = null;
            foreach (KeyValuePair<Type, string> item in _activeCategoryEditors)
            {
                if (!newCategoryEditorTypes.ContainsKey(item.Key) || !IsCategoryShown(item.Key))
                {

                    // New selection does not include this existing category editor 
                    // or the category that contains this editor
                    // so remove the editor.
                    if (editorTypesToRemove == null)
                    {
                        editorTypesToRemove = new List<Type>();
                    }

                    editorTypesToRemove.Add(item.Key);
                }
                else
                {
                    // This category editor already exists, so don't re-add it
                    newCategoryEditorTypes.Remove(item.Key);
                }
            }

            if (editorTypesToRemove != null)
            {
                foreach (Type editorTypeToRemove in editorTypesToRemove)
                {
                    ModelCategoryEntry affectedCategory = _categoryList.FindCategory(_activeCategoryEditors[editorTypeToRemove]) as ModelCategoryEntry;
                    if (affectedCategory != null)
                    {
                        affectedCategory.RemoveCategoryEditor(editorTypeToRemove);
                    }

                    _activeCategoryEditors.Remove(editorTypeToRemove);
                }
            }

            // Figure out which CategoryEditors are now required and add them
            foreach (Type editorTypeToAdd in newCategoryEditorTypes.Keys)
            {
                CategoryEditor editor = (CategoryEditor)ExtensibilityAccessor.SafeCreateInstance(editorTypeToAdd);
                if (editor == null)
                {
                    continue;
                }

                ModelCategoryEntry affectedCategory = _categoryList.FindCategory(editor.TargetCategory) as ModelCategoryEntry;
                if (affectedCategory == null)
                {
                    continue;
                }

                affectedCategory.AddCategoryEditor(editor);
                _activeCategoryEditors[editorTypeToAdd] = editor.TargetCategory;
            }
        }
        private static bool AreSelectionsEquivalent(View.Selection a, View.Selection b)
        {
            if (a == null && b == null)
            {
                return true;
            }
            if (a == null || b == null)
            {
                return false;
            }
            if (a.SelectionCount != b.SelectionCount)
            {
                return false;
            }

            // POSSIBLE OPTIMIZATION: be smarter about same selection in a different order
            IEnumerator<ModelItem> ea = a.SelectedObjects.GetEnumerator();
            IEnumerator<ModelItem> eb = b.SelectedObjects.GetEnumerator();

            while (ea.MoveNext() && eb.MoveNext())
            {
                if (!object.Equals(ea.Current, eb.Current))
                {
                    return false;
                }
            }

            return true;
        }
 // The user can only specify the name for the selected objects iff exactly one
 // object is selected.
 private static bool CanSetSelectionName(View.Selection selection)
 {
     return selection != null && selection.SelectionCount == 1;
 }
        // Looks for common parent ModelItem among all the items in the selection
        private static ModelItem GetCommonParent(View.Selection selection)
        {
            if (selection == null || selection.SelectionCount < 1)
            {
                return null;
            }

            ModelItem parent = null;
            foreach (ModelItem item in selection.SelectedObjects)
            {
                if (parent == null)
                {
                    parent = item.Parent;
                }
                else if (parent != item.Parent)
                {
                    return null;
                }
            }

            return parent;
        }
        // Removes / adds a PropertyChanged listener from / to the previous / current selection
        private void UpdateSelectionPropertyChangedEventHooks(View.Selection previousSelection, View.Selection currentSelection)
        {
            if (previousSelection != null && previousSelection.PrimarySelection != null)
            {
                previousSelection.PrimarySelection.PropertyChanged -= OnSelectedItemPropertyChanged;
            }

            if (currentSelection != null && currentSelection.PrimarySelection != null)
            {
                currentSelection.PrimarySelection.PropertyChanged += OnSelectedItemPropertyChanged;
            }
        }
        // Selection Logic

        // SelectionPathStateContainer

        // <summary>
        // Called externally whenever selection changes
        // </summary>
        // <param name="selection">New selection</param>
        public void OnSelectionChanged(View.Selection selection)
        {
            _lastNotifiedSelection = selection;
            RefreshSelection();
        }