File: cdf\src\NetFx40\Tools\System.Activities.Presentation\System\Activities\Presentation\Base\Core\Internal\PropertyEditing\Model\ModelPropertyIndexer.cs
Project: ndp\System.Data.csproj (System.Data)
//----------------------------------------------------------------
// 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.Globalization;
    using System.Text;
 
    using System.Activities.Presentation;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.PropertyEditing;
 
    using System.Activities.Presentation.Internal.Properties;
 
    // <summary>
    // ModelPropertyIndexer is used to represent ModelItems in a collection.  As such
    // and unlike ModelProperty, the class wraps around a single ModelItem instead of
    // one or more ModelProperties.
    // </summary>
    internal class ModelPropertyIndexer : ModelPropertyEntryBase 
    {
 
        private static readonly ICollection EmptyCollection = new object[0];
 
        private ModelItem _modelItem;
        private int _index;
        private ModelPropertyValueCollection _parentCollection;
 
        private CachedValues _valueCache;
 
        // <summary>
        // Basic ctor.  Note, however, that this class should only be created by ModelPropertyValueCollection
        // as that class ensures that the new instance is correctly added and removed from the
        // ModelItemMap.
        // </summary>
        // <param name="modelItem">ModelItem to wrap around</param>
        // <param name="index">Index of the ModelItem in the collection</param>
        // <param name="parentCollection">Parent collection</param>
        public ModelPropertyIndexer(
            ModelItem modelItem,
            int index,
            ModelPropertyValueCollection parentCollection)
            : base(parentCollection.ParentValue) 
        {
 
            if (modelItem == null)
            {
                throw FxTrace.Exception.ArgumentNull("modelItem");
            }
            if (parentCollection == null)
            {
                throw FxTrace.Exception.ArgumentNull("parentCollection");
            }
 
            _modelItem = modelItem;
            _index = index;
            _parentCollection = parentCollection;
            _valueCache = new CachedValues(this);
        }
 
 
        // <summary>
        // Gets the index of the underlying ModelItem.  If index &lt; 0, this
        // ModelPropertyIndexer no longer belongs to a collection and setting its value
        // will fail.
        // </summary>
        public int Index 
        {
            get {
                return _index;
            }
            internal set {
                _index = value;
            }
        }
 
        // <summary>
        // Gets the name category name of the parent collection
        // </summary>
        public override string CategoryName 
        {
            get {
                return _parentCollection.ParentValue.ParentProperty.CategoryName;
            }
        }
 
        // <summary>
        // Gets the description of the parent collection
        // </summary>
        public override string Description 
        {
            get {
                return _parentCollection.ParentValue.ParentProperty.Description;
            }
        }
 
        // <summary>
        // Gets the IsAdvanced flag of the parent collection
        // </summary>
        public override bool IsAdvanced 
        {
            get {
                return _parentCollection.ParentValue.ParentProperty.IsAdvanced;
            }
        }
 
        // <summary>
        // Returns true
        // </summary>
        public override bool IsReadOnly 
        {
            get { return true; }
        }
 
        // <summary>
        // Gets the index of this item as string
        // </summary>
        public override string PropertyName 
        {
            get {
                return _index.ToString(CultureInfo.InvariantCulture);
            }
        }
 
        // <summary>
        // Gets the type of items in the parent collection
        // </summary>
        public override Type PropertyType 
        {
            get {
                return _modelItem.ItemType;
            }
        }
 
        // <summary>
        // Returns null because there are no ValueEditors for values that belong to a collection
        // </summary>
        public override PropertyValueEditor PropertyValueEditor 
        {
            get {
                // There are no ValueEditors for items in a collection
                return null;
            }
        }
 
        // <summary>
        // Returns an empty collection - there are no StandardValues for items in a collection
        // </summary>
        public override ICollection StandardValues 
        {
            get {
                // There are no StandardValues for items in a collection
                return EmptyCollection;
            }
        }
 
        // <summary>
        // Returns false - ModelPropertyIndexers always wrap around a single ModelItem
        // </summary>
        public override bool IsMixedValue 
        {
            get { return false; }
        }
 
        // <summary>
        // Returns Local - this PropertyEntry always contains a collection item value which is local
        // </summary>
        public override PropertyValueSource Source 
        {
            get { return DependencyPropertyValueSource.Local; }
        }
 
        // <summary>
        // Gets the TypeConverter
        // </summary>
        public override TypeConverter Converter 
        {
            get {
                return _valueCache.Converter;
            }
        }
 
        // <summary>
        // Gets the Type of the contained ModelItem
        // </summary>
        public override Type CommonValueType 
        {
            get {
                return _modelItem.ItemType;
            }
        }
 
        // <summary>
        // Gets the sub-properties of the underlying item
        // </summary>
        public override PropertyEntryCollection SubProperties 
        {
            get {
                return _valueCache.SubProperties;
            }
        }
 
        // <summary>
        // Gets the collection of the underlying ModelItem
        // </summary>
        public override PropertyValueCollection Collection 
        {
            get {
                return _valueCache.Collection;
            }
        }
 
        // <summary>
        // Gets the depth of this property in the PI sub-property tree.
        // Since this class represents an item in the collection, it's depth
        // resets to -1 so that it's children start at depth 0 ( -1 + 1 = 0) again.
        // </summary>
        public override int Depth 
        {
            get {
                return -1;
            }
        }
 
 
        // <summary>
        // Gets the underlying ModelItem
        // </summary>
        internal ModelItem ModelItem 
        {
            get {
                return _modelItem;
            }
        }
 
        // <summary>
        // Gets a flag indicating whether the underlying collection instance has already been
        // initialized.  Optimization.
        // </summary>
        internal override bool CollectionInstanceExists 
        {
            get {
                return _valueCache.CollectionInstanceExists;
            }
        }
 
        // <summary>
        // Creates a new ModelPropertyValue instance
        // </summary>
        // <returns>New ModelPropertyValue instance</returns>
        protected override PropertyValue CreatePropertyValueInstance() 
        {
            return new ModelPropertyValue(this);
        }
 
        // <summary>
        // Gets the actual object instance respresented by this class
        // </summary>
        // <returns>Actual object instance respresented by this class</returns>
        public override object GetValueCore() 
        {
            return _modelItem.GetCurrentValue();
        }
 
        // <summary>
        // Sets the value of the collection item at the same position as the
        // ModelItem represented by this class.  Identical to removing the old
        // item and adding a new one
        // </summary>
        // <param name="value">Value to set</param>
        public override void SetValueCore(object value) 
        {
            throw FxTrace.Exception.AsError(new InvalidOperationException(Resources.PropertyEditing_ErrorSetValueOnIndexer));
        }
 
        // <summary>
        // Throws an exception -- invalid operation
        // </summary>
        public override void ClearValue() 
        {
            throw FxTrace.Exception.AsError(new InvalidOperationException(Resources.PropertyEditing_ClearIndexer));
        }
 
        // <summary>
        // Opens a new ModelEditingScope with the specified description.
        // </summary>
        // <param name="description">Change description (may be null).</param>
        // <returns>New, opened ModelEditingScope with the specified description</returns>
        internal override ModelEditingScope BeginEdit(string description) 
        {
            return description == null ? _modelItem.BeginEdit() : _modelItem.BeginEdit(description);
        }
 
        // <summary>
        // Called when one of the sub-properties exposed by this class changes
        // </summary>
        protected override void OnUnderlyingSubModelChangedCore() 
        {
            // Do nothing.  There is nothing in CachedValues right now that would need to
            // be refreshed as a result of one of our sub-properties changing value
        }
 
        // Cached values that need to be nixed when the underlying ModelItem changes
        // (ie. someone calls SetValueCore()).  Pretty much everything in here is an "expensive"
        // calculation which requires us to evaluate some attributes associated with the given
        // property of set of properties, so we cache the return values and keep that cache
        // in a single place so that it's easy to know what needs to be ----d when the underlying
        // ModelItem changes.
        private class CachedValues 
        {
 
            private static readonly TypeConverter NoTypeConverter = new TypeConverter();
 
            private ModelPropertyIndexer _parent;
 
            private TypeConverter _converter;
            private ModelPropertyEntryCollection _subProperties;
            private ModelPropertyValueCollection _collection;
 
            public CachedValues(ModelPropertyIndexer indexer) 
            {
                _parent = indexer;
            }
 
            public TypeConverter Converter 
            {
                get {
                    if (_converter == null) 
                    {
                        _converter = ExtensibilityAccessor.GetTypeConverter(_parent._modelItem);
                        _converter = _converter ?? NoTypeConverter;
                    }
 
                    return _converter == NoTypeConverter ? null : _converter;
                }
            }
 
            public ModelPropertyEntryCollection SubProperties 
            {
                get {
                    if (_subProperties == null)
                    {
                        _subProperties = new ModelPropertyEntryCollection(_parent);
                    }
 
                    return _subProperties;
                }
            }
 
            public bool CollectionInstanceExists 
            {
                get {
                    return _collection != null;
                }
            }
 
            public ModelPropertyValueCollection Collection 
            {
                get {
                    if (_collection == null)
                    {
                        _collection = new ModelPropertyValueCollection(_parent.ModelPropertyValue);
                    }
 
                    return _collection;
                }
            }
        }
    }
}