File: System.Activities.Presentation\System\Activities\Presentation\View\TypeKeyValue.cs
Project: ndp\cdf\src\NetFx40\Tools\System.Activities.Presentation.csproj (System.Activities.Presentation)
namespace System.Activities.Presentation.View
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Automation.Peers;
    using System.Windows.Input;
 
    //helper class, used to resolve generics. supports cascading generic type arguments (i.e. IList< IList < int > >)
    internal class TypeKeyValue : INotifyPropertyChanged
    {
        string errorText;
        //generic type
        Type genericType;
 
        bool isValid = true;
        //generic's type generic parameters
        ObservableCollection<TypeKeyValue> subTypes = new ObservableCollection<TypeKeyValue>();
        //target type
        Type targetType;
        //type resolver reference
        Action<TypeKeyValue> typeChangedCallBack;
        //if this type is selected
        bool isSelected;
        Func<Type, bool> filter;
        ObservableCollection<Type> mostRecentlyUsedTypes;
        string hintText = null;
        //if type presenter should skip the drop down list
        bool browseTypeDirectly = true;
 
        public TypeKeyValue(Type genericType, Action<TypeKeyValue> typeChangedCallBack)
        {
            this.GenericType = genericType;
            this.typeChangedCallBack = typeChangedCallBack;
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        public string ErrorText
        {
            get { return this.errorText; }
            set
            {
                this.errorText = value;
                OnPropertyChanged("ErrorText");
            }
        }
 
        public Type GenericType
        {
            get { return this.genericType; }
            set
            {
                this.genericType = value;
                OnPropertyChanged("GenericType");
            }
        }
 
        public bool IsSelected
        {
            get { return this.isSelected; }
            set
            {
                this.isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
 
        public Func<Type, bool> Filter
        {
            get { return this.filter; }
            set
            {
                this.filter = value;
                OnPropertyChanged("Filter");
            }
        }
 
        public ObservableCollection<Type> MostRecentlyUsedTypes
        {
            get { return this.mostRecentlyUsedTypes; }
            set
            {
                this.mostRecentlyUsedTypes = value;
                OnPropertyChanged("MostRecentlyUsedTypes");
            }
        }
 
        public string HintText
        {
            get { return this.hintText; }
            set
            {
                this.hintText = value;
                this.OnPropertyChanged("HintText");
            }
        }
 
        public bool BrowseTypeDirectly
        {
            get { return this.browseTypeDirectly; }
            set
            {
                this.browseTypeDirectly = value;
                OnPropertyChanged("BrowseTypeDirectly");
            }
        }
 
        public bool IsValid
        {
            get { return this.isValid; }
            set
            {
                this.isValid = value;
                OnPropertyChanged("IsValid");
            }
        }
 
 
        public ObservableCollection<TypeKeyValue> SubTypes
        {
            get { return this.subTypes; }
        }
 
        public Type TargetType
        {
            get { return this.targetType; }
            set
            {
                this.targetType = value;
                //whenever target type changes, check if there are some generic parameters required
                LoadGenericTypes();
                OnPropertyChanged("TargetType");
                if (typeChangedCallBack != null)
                {
                    typeChangedCallBack(this);
                }
            }
        }
 
        public Type GetConcreteType()
        {
            Type result = null;
            if (null != this.targetType)
            {
                //do we have generic?
                if (this.targetType.IsGenericTypeDefinition)
                {
                    //resolve all generic arguments
                    Type[] arguments = new Type[this.subTypes.Count];
                    bool isValid = true;
                    for (int i = 0; i < this.subTypes.Count && isValid; ++i)
                    {
                        arguments[i] = this.subTypes[i].GetConcreteType();
                        isValid = (null != arguments[i]);
                    }
                    if (isValid)
                    {
                        //and create target type
                        result = this.targetType.MakeGenericType(arguments);
                    }
                }
                else
                {
                    result = targetType;
                }
            }
            return result;
        }
 
        void LoadGenericTypes()
        {
            this.subTypes.Clear();
            if (null != this.targetType && this.targetType.IsGenericTypeDefinition)
            {
                Type[] generics = this.targetType.GetGenericArguments();
                foreach (Type t in generics)
                {
                    TypeKeyValue entry = new TypeKeyValue(t, typeChangedCallBack);
                    this.subTypes.Add(entry);
                    typeChangedCallBack(entry);
                }
            }
        }
 
        void OnPropertyChanged(string propertyName)
        {
            if (null != PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
 
    }
}