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