// <summary> // Gets the underlying ModelItemCollection // </summary> // <returns>The underlying ModelItemCollection</returns> internal ModelItemCollection GetRawCollection() { ModelPropertyEntry parentAsEntry = ParentValue.ParentProperty as ModelPropertyEntry; if (parentAsEntry != null) { return(parentAsEntry.FirstModelProperty.Collection); } ModelPropertyIndexer parentAsIndexer = ParentValue.ParentProperty as ModelPropertyIndexer; if (parentAsIndexer != null) { ModelItemCollection modelItemCollection = parentAsIndexer.ModelItem as ModelItemCollection; // If the parent is an indexer, that means we are a collection within another collection // and the ModelItem of the indexer is really a ModelItemCollection. Fx.Assert(modelItemCollection != null, "modelItemCollection should not be null"); return(modelItemCollection); } Debug.Fail("A new class was introduced that derives from PropertyEntry. Need to update ModelPropertyValueCollection code as well."); return(null); }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string result = null; if (value != null) { ModelPropertyEntry modelPropertyEntry = value as ModelPropertyEntry; if (modelPropertyEntry != null) { StringBuilder propertyPath = new StringBuilder(modelPropertyEntry.PropertyName); propertyPath.Insert(0, '.'); ModelProperty property = modelPropertyEntry.FirstModelProperty; if (property != null) { ModelItem convertedValue = property.Parent; while (convertedValue != null && !typeof(Activity).IsAssignableFrom(convertedValue.ItemType)) { if (null != convertedValue.Source) { propertyPath.Insert(0, convertedValue.Source.Name); propertyPath.Insert(0, '.'); } convertedValue = convertedValue.Parent; } } propertyPath.Remove(0, 1); result = propertyPath.ToString(); } } return(result); }
internal static ModelItem Convert(ModelPropertyEntry modelPropertyEntry, bool returnParentActivity) { ModelItem convertedValue = null; if (modelPropertyEntry != null) { ModelProperty property = modelPropertyEntry.FirstModelProperty; if (property != null) { convertedValue = property.Parent; if (returnParentActivity) { while (convertedValue != null) { Type itemType = convertedValue.ItemType; if (typeof(Activity).IsAssignableFrom(itemType) || typeof(WorkflowService).IsAssignableFrom(itemType)) { break; } convertedValue = convertedValue.Parent; } } } } return(convertedValue); }
private static int CompareCore(object x, object y) { ModelPropertyEntry j = x as ModelPropertyEntry; ModelPropertyEntry k = y as ModelPropertyEntry; if (j == null && k == null) { return(0); } if (j == null) { return(-1); } if (k == null) { return(1); } PropertyOrder a = j.PropertyOrder ?? DefaultOrder; PropertyOrder b = k.PropertyOrder ?? DefaultOrder; int result = a.CompareTo(b); return(result != 0 ? result : string.Compare(j.DisplayName, k.DisplayName, StringComparison.CurrentCulture)); }
// <summary> // Basic ctor // </summary> // <param name="property">Property to display</param> // <param name="valueDialogTemplate">Template to use</param> public PropertyValueDialogControl(PropertyEntry property, DataTemplate valueDialogTemplate) { Fx.Assert(property != null, "property parameter is null"); Fx.Assert(valueDialogTemplate != null, "valueDialogTemplate parameter is null"); ModelPropertyEntry modelPropertyValue = property as ModelPropertyEntry; if (modelPropertyValue != null) { _rootTransaction = modelPropertyValue.FirstModelProperty.Value.BeginEdit(); } InitializeComponent(); // Make sure we use PI-specific resources within this control this.Resources.MergedDictionaries.Add(PropertyInspectorResources.GetResources()); // Hook into an opening of nested dialogs. PropertyInspector class takes care of this for us. // However, we are using Blend's collection editor which doesn't do the same thing, so // we need to reproduce that behavior manually. PropertyValueDialogHost.AttachOpenDialogHandlers(this); // Hook into the standard set of Commands _defaultCommandHandler = new PropertyValueEditorCommandHandler(this); _OKButton.Click += new RoutedEventHandler(OnOkButtonClicked); _cancelButton.Click += new RoutedEventHandler(OnCancelButtonClicked); _contentControl.Content = property.PropertyValue; _contentControl.ContentTemplate = valueDialogTemplate; //Handle the commit and cancel keys within the property inspector, that is hosted in the collection editor ValueEditorUtils.SetHandlesCommitKeys(this, true); }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { FlowDirection returnValue = FlowDirection.LeftToRight; Fx.Assert(values.Length == 3, "Incorrect values in the MultiValueConverter!"); if (values.Length == 3) { ModelPropertyEntry propertyEntry = values[1] as ModelPropertyEntry; if (propertyEntry != null) { if (!propertyEntry.DisplayName.Equals("Name")) { if (targetType == typeof(FlowDirection)) { object propertyValue = values[0]; if (propertyValue == null || propertyValue.GetType() == typeof(string)) { //customize it to controls FlowDirection Property returnValue = (FlowDirection)PropertyInspectorResources.GetResources()["SelectedControlFlowDirectionRTL"]; } } } } } return(returnValue); }
// ShowCategoryHeader DP // In Cider and unlike in Blend, we expose all properties (browsable and non-browsable) through the // property editing object model. Hence, we need to make sure that the UI representing it (CategoryContainer) // does the filtering instead. This is by design and, for consistency, it should be pushed into Blend as well protected override void AddProperty(PropertyEntry property, ObservableCollection <PropertyEntry> unconsumedProperties, ObservableCollection <PropertyEntry> referenceOrder, ObservableCollection <CategoryEditor> categoryEditors) { // Is this property browsable? ModelPropertyEntry modelPropertyEntry = property as ModelPropertyEntry; if (modelPropertyEntry != null && !modelPropertyEntry.IsBrowsable) { return; } // Yes, so we can safely add it to the list base.AddProperty(property, unconsumedProperties, referenceOrder, categoryEditors); }
// IPropertyViewManager Members // <summary> // Add a property into the correct category within the specified CategoryList. // </summary> // <param name="propertySet">Specified property (passed in as a set for multi-select scenarios)</param> // <param name="propertyName">Name of the current property (perf optimization)</param> // <param name="categoryList">CategoryList instance to populate</param> // <returns>Wrapped ModelPropertyEntry for the specified propertySet</returns> public ModelPropertyEntry AddProperty(IEnumerable <ModelProperty> propertySet, string propertyName, CategoryList categoryList) { string categoryName = GetCategoryName(propertySet); ModelCategoryEntry category = categoryList.FindCategory(categoryName) as ModelCategoryEntry; bool reuseEntries = ExtensibilityAccessor.IsEditorReusable(propertySet); if (reuseEntries && category != null) { ModelPropertyEntry foundProperty; if ((foundProperty = (ModelPropertyEntry)category[propertyName]) != null) { if (foundProperty.PropertyType != null && foundProperty.PropertyType.Equals(System.Activities.Presentation.Internal.PropertyEditing.Model.ModelUtilities.GetPropertyType(propertySet))) { // Found a match for the property, so reuse it bool oldIsBrowsable = foundProperty.IsBrowsable; bool oldIsAdvanced = foundProperty.IsAdvanced; foundProperty.SetUnderlyingModelProperty(propertySet); // If the IsBrowsable or IsAdvanced value of the property changed, // refresh the property within the category, because how and whether // this property should be rendered may have changed. // Note that refreshing a selected property also nullifies its stickiness // (ie. it resets CategoryList.PropertySelectionMode) if (oldIsAdvanced != foundProperty.IsAdvanced || oldIsBrowsable != foundProperty.IsBrowsable) { category.Refresh(foundProperty, category.GetBucket(foundProperty), this.PropertyComparer); } return(foundProperty); } } } if (category == null) { category = new ModelCategoryEntry(categoryName); categoryList.InsertAlphabetically(category); } ModelPropertyEntry property = new ModelPropertyEntry(propertySet, null); category.Add(property, category.GetBucket(property), this.PropertyComparer); return(property); }
private static bool CullDisassociatedProperties(ObservableCollectionWorkaround <PropertyEntry> propertyList) { bool propertiesCulled = false; for (int i = propertyList.Count - 1; i >= 0; i--) { ModelPropertyEntry property = (ModelPropertyEntry)propertyList[i]; if (property.Disassociated) { property.Disconnect(); propertyList.RemoveAt(i); propertiesCulled = true; } } return(propertiesCulled); }
// Another Blend work-around - we expose all properties through the OM, not just the // Browsable ones. However, as a result, we need to cull the non-browsable ones from // consideration. Otherwise, empty categories may appear. protected override bool DoesPropertyMatchFilter(PropertyFilter filter, PropertyEntry property) { property.ApplyFilter(filter); bool isBrowsable = true; ModelPropertyEntry modelPropertyEntry = property as ModelPropertyEntry; if (modelPropertyEntry != null) { //display given property if it is browsable or isBrowsable = modelPropertyEntry.IsBrowsable || // it may not be browsable, but if there is a category editor associated - display it anyway (this.CategoryEditors != null && this.CategoryEditors.Count != 0); } return(isBrowsable && property.MatchesFilter); }
private void CreateCollection(ModelPropertyEntry parentProperty) { // Assert some assumptions that should be true at this point Fx.Assert(parentProperty != null, "parentProperty should not be null"); Fx.Assert(parentProperty.ModelPropertySet != null, "parentProperty.ModelPropertySet should not be null"); Fx.Assert(parentProperty.ModelPropertySet.Count > 0, "parentProperty.ModelPropertySet.Count should be > 0"); // Ignore sub-properties of MarkupExtensions for v1 if (parentProperty.IsMarkupExtension) { return; } IEnumerable <IList <ModelProperty> > mergedSubProperties = ModelPropertyMerger.GetMergedSubProperties(parentProperty.ModelPropertySet); int index = 0; bool multiSelect = parentProperty.ModelPropertySet.Count > 1; foreach (IList <ModelProperty> subPropertySet in mergedSubProperties) { if (index == 0) { _properties = new List <ModelPropertyEntry>(); } ModelPropertyEntry entry; if (multiSelect) { entry = new ModelPropertyEntry(subPropertySet, (ModelPropertyValue)parentProperty.PropertyValue); } else { entry = new ModelPropertyEntry(subPropertySet[0], (ModelPropertyValue)parentProperty.PropertyValue); } _properties.Add(entry); index++; } // Sort the sub-properties by their OrderToken as well as their name if (_properties != null) { _properties.Sort(); } }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { ModelItem convertedValue = null; if (values[1] != null) { ModelPropertyEntry modelPropertyEntry = values[1] as ModelPropertyEntry; if (modelPropertyEntry != null) { ModelProperty property = modelPropertyEntry.FirstModelProperty; if (property != null) { convertedValue = property.Value; } } } return(convertedValue); }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { PropertyEntry propertyEntry = value as PropertyEntry; if (null == propertyEntry) { PropertyValue propertyValue = value as PropertyValue; if (null != propertyValue) { propertyEntry = propertyValue.ParentProperty; } } ModelPropertyEntry modelPropertyEntry = propertyEntry as ModelPropertyEntry; ModelProperty modelProperty = null; if (modelPropertyEntry != null) { modelProperty = modelPropertyEntry.FirstModelProperty; } if (modelProperty == null) { return(Binding.DoNothing); } string optionName = parameter as string; if (optionName == null) { return(Binding.DoNothing); } object optionValue; if (EditorOptionAttribute.TryGetOptionValue(modelProperty.Attributes, optionName, out optionValue)) { return(optionValue); } return(Binding.DoNothing); }
private static int CompareCore(object x, object y) { ModelPropertyEntry j = x as ModelPropertyEntry; ModelPropertyEntry k = y as ModelPropertyEntry; if (j == null && k == null) { return(0); } if (j == null) { return(-1); } if (k == null) { return(1); } return(string.Compare(j.DisplayName, k.DisplayName, StringComparison.CurrentCulture)); }
// <summary> // Removes and re-adds the specified property from this category, if it existed // there to begin with. Noop otherwise. // // Use this method to refresh the cate----zation of a property if it suddenly // becomes Advanced if it was Basic before, or if its IsBrowsable status changes. // </summary> // <param name="property">Property to refresh</param> // <param name="bucket">Property bucket to repopulate</param> // <param name="sortComparer">Comparer to use to reinsert the given property in its new place</param> internal void Refresh(ModelPropertyEntry property, ObservableCollection <PropertyEntry> bucket, IComparer <PropertyEntry> sortComparer) { if (property == null) { throw FxTrace.Exception.ArgumentNull("property"); } if (bucket != _basicProperties && bucket != _advancedProperties) { Debug.Fail("Invalid bucket specified. Property was not refreshed."); return; } // Let's see if we know about this property ObservableCollectionWorkaround <PropertyEntry> collection; collection = _advancedProperties; int index = collection.BinarySearch(property, null); if (index < 0) { collection = _basicProperties; index = collection.BinarySearch(property, null); } // If not, noop if (index < 0) { return; } // We know about this property, so refresh it. It may have changed // somehow (eg. switched from basic to advanced, become hidden, etc.) // so make sure it's thrown into the right bucket. collection.RemoveAt(index); Add(property, bucket, sortComparer, false); }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { ModelItem convertedValue = null; if (values[1] != null) { ModelPropertyEntry modelPropertyEntry = values[1] as ModelPropertyEntry; if (modelPropertyEntry != null) { ModelProperty property = modelPropertyEntry.FirstModelProperty; if (property != null) { ModelItem argumentModelItem = property.Value; if (argumentModelItem != null && argumentModelItem.Properties["Expression"] != null && argumentModelItem.Properties["Expression"].Value != null) { convertedValue = argumentModelItem.Properties["Expression"].Value; } } } } return(convertedValue); }
// 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(); }
// <summary> // Same as GetSubPropertyHierarchyPath(), but it looks up a cached version // of this path, if one exists, or calculates one from scratch and caches it // if it doesn't. // </summary> // <param name="property">Property to get the name of</param> // <returns>',' separated property name for sub-properties</returns> public static string GetCachedSubPropertyHierarchyPath(PropertyEntry property) { ModelPropertyEntry mpe = property as ModelPropertyEntry; return(mpe == null?GetSubPropertyHierarchyPath(property) : mpe.SubPropertyHierarchyPath); }
// <summary> // Basic ctor // </summary> // <param name="parentProperty">Parent property</param> public ModelPropertyEntryCollection(ModelPropertyEntry parentProperty) : base(parentProperty.PropertyValue) { CreateCollection(parentProperty); }