// 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(); }