//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.Activities.Presentation.Internal.PropertyEditing.Model
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Windows.Markup;
using System.Activities.Presentation.Model;
using System.Activities.Presentation.PropertyEditing;
//
// Static class full of useful helpers
//
internal static class ModelUtilities
{
public static Type GetPropertyType(IEnumerable propertySet)
{
// all the ModelProperty should be of the same type, so returning the first type.
foreach (ModelProperty property in propertySet)
{
return property.PropertyType;
}
return null;
}
//
// Compares the name and Type of the specified ModelProperties,
// returning true if they are equal.
//
// ModelProperty A
// ModelProperty B
// True if the names and Types of the specified ModelProperties
// match, false otherwise.
public static bool AreEquivalent(ModelProperty a, ModelProperty b)
{
return object.Equals(a.Name, b.Name) &&
object.Equals(a.PropertyType, b.PropertyType);
}
//
// Gets the underlying value object of the specified ModelProperty. MarkupExtensions
// (resources and such) will be returned as they are, with the exception of NullExtension,
// which will be returned as null.
//
// ModelProperty to ---- open (can be null)
// Underlying value object, if any
public static object GetSafeRawValue(ModelProperty property)
{
return GetSafeValue(property, false);
}
//
// Gets the underlying computed value object of the specified ModelProperty. MarkupExtensions
// (resources and such) will be resolved into their final value.
//
// ModelProperty to ---- open (can be null)
// Underlying value object, if any
public static object GetSafeComputedValue(ModelProperty property)
{
return GetSafeValue(property, true);
}
private static object GetSafeValue(ModelProperty property, bool resolveReferences)
{
if (property == null)
{
return null;
}
object value;
// We have to special case TextBlock due to IAddChild behavior with Text and Inlines
if (resolveReferences && !(typeof(System.Windows.Controls.TextBlock).IsAssignableFrom(property.Parent.ItemType) &&
property.Name.Equals(System.Windows.Controls.TextBlock.TextProperty.Name)))
{
value = property.ComputedValue;
}
else
{
value = property.Value == null ? null : property.Value.GetCurrentValue();
}
if (value == null || value.GetType().Equals(typeof(NullExtension)))
{
return null;
}
return value;
}
//
// Looks for the x:Name or Name property of the given PropertyValue and returns it if found.
// Note: this method is expensive because it evaluates all the sub-properties of the given
// PropertyValue.
//
// PropertyValue instance to look at
// Name if the PropertyValue defines one, null otherwise
public static string GetPropertyName(PropertyValue propertyValue)
{
if (propertyValue == null)
{
return null;
}
if (propertyValue.HasSubProperties)
{
PropertyEntry nameProperty = propertyValue.SubProperties["Name"];
if (nameProperty != null)
{
return nameProperty.PropertyValue.StringValue;
}
}
return null;
}
//
// Returns ',' separated property name for sub-properties, going all the way
// to the root ancestor in the property editing OM. (ie. you get strings
// such as 'ContextMenu,IsEnabled' instead of just 'IsEnabled'.
//
// Property to get the name of
// ',' separated property name for sub-properties
public static string GetSubPropertyHierarchyPath(PropertyEntry property)
{
if (property == null)
{
return null;
}
if (property.ParentValue == null)
{
return property.PropertyName;
}
StringBuilder sb = new StringBuilder();
do
{
if (sb.Length > 0)
{
sb.Insert(0, ',');
}
sb.Insert(0, property.PropertyName);
property = property.ParentValue == null ? null : property.ParentValue.ParentProperty;
} while (property != null && !(property is ModelPropertyIndexer));
return sb.ToString();
}
//
// 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.
//
// Property to get the name of
// ',' separated property name for sub-properties
public static string GetCachedSubPropertyHierarchyPath(PropertyEntry property)
{
ModelPropertyEntry mpe = property as ModelPropertyEntry;
return mpe == null ? GetSubPropertyHierarchyPath(property) : mpe.SubPropertyHierarchyPath;
}
//
// Determines whether the specified type is implement generic Ilist interface.
//
// The type.
//
// true if the specified type is implement generic Ilist interface;otherwise, false.
//
public static bool ImplementsIList(Type type)
{
bool ret = false;
if (!type.IsGenericType)
{
ret = false;
}
Type[] interfaceTypes = type.GetInterfaces();
foreach (Type interfaceType in interfaceTypes)
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition() == typeof(IList<>))
{
ret = true;
break;
}
}
return ret;
}
//
// Determines whether the specified type is implement generic ICollection interface.
//
// The type.
//
// true if the specified type is implement generic ICollection interface;otherwise, false.
//
public static bool ImplementsICollection(Type type)
{
bool ret = false;
if (!type.IsGenericType)
{
ret = false;
}
Type[] interfaceTypes = type.GetInterfaces();
foreach (Type interfaceType in interfaceTypes)
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
ret = true;
break;
}
}
return ret;
}
//
// Tries to determine the common type ancestor of the specified types
//
// Type 1
// Type 2
// Common ancestor Type, if any
public static Type GetCommonAncestor(Type t1, Type t2)
{
if (t1 == null || t2 == null)
{
return null;
}
if (t1 == typeof(object) || t2 == typeof(object))
{
return typeof(object);
}
if (t1.IsAssignableFrom(t2))
{
return t1;
}
while (t2 != typeof(object))
{
if (t2.IsAssignableFrom(t1))
{
return t2;
}
t2 = t2.BaseType;
}
return typeof(object);
}
}
}