File: System.Activities.Presentation\System\Activities\Presentation\Base\Core\Internal\PropertyEditing\Model\ModelPropertyEntryBase.cs
Project: ndp\cdf\src\NetFx40\Tools\System.Activities.Presentation.csproj (System.Activities.Presentation)
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------
namespace System.Activities.Presentation.Internal.PropertyEditing.Model 
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Text;
 
    using System.Activities.Presentation;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.PropertyEditing;
    using System.Activities.Presentation.Services;
 
    // <summary>
    // Cider-specific base class for PropertyEntry.  It is shared by both
    // ModelPropertyEntry and ModelPropertyIndexer.  ModelPropertyEntry is used
    // to model regular properties that are backed by Cider's ModelProperty.
    // ModelPropertyIndexers are used to model items in collections that are
    // backed by Cider's ModelItems.
    // </summary>
    internal abstract class ModelPropertyEntryBase : PropertyEntry 
    {
 
        // Cache the depth of this property because once a property entry is create
        // it doesn't jump levels.  Depth is only used to track sub-property tree's
        // not collection trees.
        private int _depth;
        private string _propertyPath;
 
        protected ModelPropertyEntryBase() : this(null) 
        {
        }
        protected ModelPropertyEntryBase(PropertyValue parentValue) : base(parentValue) 
        {
            UpdateDepth();
        }
 
        public abstract PropertyValueSource Source 
        { get; }
        public abstract bool IsMixedValue 
        { get; }
        public abstract Type CommonValueType 
        { get; }
        public abstract TypeConverter Converter 
        { get; }
 
        // <summary>
        // Gets a flag indicating whether this property exposes any sub-properties.
        // We rely on TypeConverter.GetPropertiesSupported() for this value.
        // </summary>
        public bool HasSubProperties 
        {
            get {
                return this.PropertyValue.Value != null && this.Converter != null &&
                    this.Converter.GetPropertiesSupported() && !this.IsMarkupExtension;
            }
        }
 
        public abstract PropertyEntryCollection SubProperties 
        { get; }
 
        // <summary>
        // Gets a flag indicating whether the type of the contained property
        // can be assigned to an IList
        // </summary>
        public bool IsCollection 
        {
            get {
                return typeof(IList).IsAssignableFrom(this.PropertyType);
            }
        }
        public abstract PropertyValueCollection Collection 
        { get; }
 
        // <summary>
        // Gets the depth of this property in the PI sub-property tree
        // </summary>
        public virtual int Depth 
        {
            get {
                return _depth;
            }
        }
 
        // <summary>
        // Gets a ',' separated path of this property through its
        // sub-property hierarchy.
        // </summary>
        public string SubPropertyHierarchyPath 
        {
            get {
                if (_propertyPath == null)
                {
                    _propertyPath = ModelUtilities.GetSubPropertyHierarchyPath(this);
                }
 
                return _propertyPath;
            }
        }
 
        // <summary>
        // Checks to see if the value of this property comes from a MarkupExtension
        // </summary>
        internal bool IsMarkupExtension 
        {
            get {
                DependencyPropertyValueSource source = this.Source as DependencyPropertyValueSource;
                return source != null && source.IsExpression;
            }
        }
 
        internal abstract bool CollectionInstanceExists 
        { get; }
 
        // <summary>
        // Convenience accessor
        // </summary>
        protected ModelPropertyValue ModelPropertyValue 
        {
            get {
                return (ModelPropertyValue)this.PropertyValue;
            }
        }
        public abstract object GetValueCore();
        public abstract void SetValueCore(object value);
        public abstract void ClearValue();
 
        // Calculate the depth of this property in the sub-property
        // hierarchy
        //
        private void UpdateDepth() 
        {
            if (ParentValue != null)
            {
                _depth = ((ModelPropertyEntryBase)ParentValue.ParentProperty).Depth + 1;
            }
        }
 
        // <summary>
        // Called when one of the sub-properties exposed by this class changes.
        // There is a call to the concrete implementation of this class so that it
        // can do any internal cache clean up as needed, followed by the firing
        // of the appropriate changed events.
        // </summary>
        public void OnUnderlyingSubModelChanged() 
        {
            OnUnderlyingSubModelChangedCore();
            this.ModelPropertyValue.OnUnderlyingSubModelChanged();
        }
 
        // <summary>
        // Called when one of the sub-properties exposed by this class changes
        // that allows the concrete implementation of this class to clean up
        // any internal state.
        // </summary>
        protected abstract void OnUnderlyingSubModelChangedCore();
 
        // <summary>
        // Clears or updates any cached values - call this method
        // when the underlying ModelProperty changes and cached values
        // may have become invalid
        // </summary>
        protected virtual void RefreshCache() 
        {
            UpdateDepth();
            _propertyPath = null;
        }
 
        internal abstract ModelEditingScope BeginEdit(string description);
    }
}