[corlib] Avoid unnecessary ephemeron array resizes
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Base / Core / Internal / PropertyEditing / Model / ModelPropertyEntryBase.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.Activities.Presentation.Internal.PropertyEditing.Model 
5 {
6     using System;
7     using System.Collections;
8     using System.Collections.Generic;
9     using System.ComponentModel;
10     using System.Diagnostics;
11     using System.Text;
12
13     using System.Activities.Presentation;
14     using System.Activities.Presentation.Model;
15     using System.Activities.Presentation.PropertyEditing;
16     using System.Activities.Presentation.Services;
17
18     // <summary>
19     // Cider-specific base class for PropertyEntry.  It is shared by both
20     // ModelPropertyEntry and ModelPropertyIndexer.  ModelPropertyEntry is used
21     // to model regular properties that are backed by Cider's ModelProperty.
22     // ModelPropertyIndexers are used to model items in collections that are
23     // backed by Cider's ModelItems.
24     // </summary>
25     internal abstract class ModelPropertyEntryBase : PropertyEntry 
26     {
27
28         // Cache the depth of this property because once a property entry is create
29         // it doesn't jump levels.  Depth is only used to track sub-property tree's
30         // not collection trees.
31         private int _depth;
32         private string _propertyPath;
33
34         protected ModelPropertyEntryBase() : this(null) 
35         {
36         }
37         protected ModelPropertyEntryBase(PropertyValue parentValue) : base(parentValue) 
38         {
39             UpdateDepth();
40         }
41
42         public abstract PropertyValueSource Source 
43         { get; }
44         public abstract bool IsMixedValue 
45         { get; }
46         public abstract Type CommonValueType 
47         { get; }
48         public abstract TypeConverter Converter 
49         { get; }
50
51         // <summary>
52         // Gets a flag indicating whether this property exposes any sub-properties.
53         // We rely on TypeConverter.GetPropertiesSupported() for this value.
54         // </summary>
55         public bool HasSubProperties 
56         {
57             get {
58                 return this.PropertyValue.Value != null && this.Converter != null &&
59                     this.Converter.GetPropertiesSupported() && !this.IsMarkupExtension;
60             }
61         }
62
63         public abstract PropertyEntryCollection SubProperties 
64         { get; }
65
66         // <summary>
67         // Gets a flag indicating whether the type of the contained property
68         // can be assigned to an IList
69         // </summary>
70         public bool IsCollection 
71         {
72             get {
73                 return typeof(IList).IsAssignableFrom(this.PropertyType);
74             }
75         }
76         public abstract PropertyValueCollection Collection 
77         { get; }
78
79         // <summary>
80         // Gets the depth of this property in the PI sub-property tree
81         // </summary>
82         public virtual int Depth 
83         {
84             get {
85                 return _depth;
86             }
87         }
88
89         // <summary>
90         // Gets a ',' separated path of this property through its
91         // sub-property hierarchy.
92         // </summary>
93         public string SubPropertyHierarchyPath 
94         {
95             get {
96                 if (_propertyPath == null)
97                 {
98                     _propertyPath = ModelUtilities.GetSubPropertyHierarchyPath(this);
99                 }
100
101                 return _propertyPath;
102             }
103         }
104
105         // <summary>
106         // Checks to see if the value of this property comes from a MarkupExtension
107         // </summary>
108         internal bool IsMarkupExtension 
109         {
110             get {
111                 DependencyPropertyValueSource source = this.Source as DependencyPropertyValueSource;
112                 return source != null && source.IsExpression;
113             }
114         }
115
116         internal abstract bool CollectionInstanceExists 
117         { get; }
118
119         // <summary>
120         // Convenience accessor
121         // </summary>
122         protected ModelPropertyValue ModelPropertyValue 
123         {
124             get {
125                 return (ModelPropertyValue)this.PropertyValue;
126             }
127         }
128         public abstract object GetValueCore();
129         public abstract void SetValueCore(object value);
130         public abstract void ClearValue();
131
132         // Calculate the depth of this property in the sub-property
133         // hierarchy
134         //
135         private void UpdateDepth() 
136         {
137             if (ParentValue != null)
138             {
139                 _depth = ((ModelPropertyEntryBase)ParentValue.ParentProperty).Depth + 1;
140             }
141         }
142
143         // <summary>
144         // Called when one of the sub-properties exposed by this class changes.
145         // There is a call to the concrete implementation of this class so that it
146         // can do any internal cache clean up as needed, followed by the firing
147         // of the appropriate changed events.
148         // </summary>
149         public void OnUnderlyingSubModelChanged() 
150         {
151             OnUnderlyingSubModelChangedCore();
152             this.ModelPropertyValue.OnUnderlyingSubModelChanged();
153         }
154
155         // <summary>
156         // Called when one of the sub-properties exposed by this class changes
157         // that allows the concrete implementation of this class to clean up
158         // any internal state.
159         // </summary>
160         protected abstract void OnUnderlyingSubModelChangedCore();
161
162         // <summary>
163         // Clears or updates any cached values - call this method
164         // when the underlying ModelProperty changes and cached values
165         // may have become invalid
166         // </summary>
167         protected virtual void RefreshCache() 
168         {
169             UpdateDepth();
170             _propertyPath = null;
171         }
172
173         internal abstract ModelEditingScope BeginEdit(string description);
174     }
175 }