PropertyPath.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / PropertyPath.cs / 1 / PropertyPath.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: PropertyPath.cs 
//
// Description: 
//     Used to describe a property as a "path" below another property. 
//
// Example: "Background.Opacity" is a path.  It implies: 
//     * Find the Background property, get the value object of that property.
//     * What we want is the Opacity property on that object.
//
//--------------------------------------------------------------------------- 

using System.ComponentModel; 
using System.Diagnostics; 
using System.Globalization;
using System.Reflection; 
using System.Text;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized; 
using System.Windows.Data;
using System.Windows.Threading; 
 
using System.Windows.Markup;
using MS.Internal; 
using MS.Internal.Data;
using MS.Utility;           // FrugalList

// A property path really consists of two parts: a static part (PropertyPath) 
// that describes the path, and a dynamic part (PropertyPathWorker) that knows
// how to evaluate the path, relative to a "root item". 
// 
// PropertyPath supports two modes of behavior:
// 
// "Source" mode is appropriate when the path describes a "source" - some place
// from which we'll fetch values.  The user of PropertyPath typically creates
// workers explicitly - one for each root item - and calls them directly.  The
// workers are fully dynamic;  they listen for property and currency change 
// events, maintain dependency sources, etc.  The connection between the worker
// and its root item is long-lived.  This mode is used by the Binding class in 
// support of data binding. 
//
// "Target" mode is appropriate when the path describes a "target" - some place 
// into which we'll store values.  The user of PropertyPath typically does not
// create workers, but rather calls the convenience routines in PropertyPath
// (relying on the implicit "single" worker).  The connection between the
// worker and its root item is short-lived;  the caller typically connects to 
// a root item, calls a few methods, then disconnects.  This mode is used by
// the property engine and by animation in support of timeline setters. 
 
namespace System.Windows
{ 
    internal enum PropertyPathStatus { Inactive, Active, PathError, AsyncRequestPending }

    internal struct IndexerParameterInfo
    { 
        public Type type;       // user-specified type
        public object value;    // string or strongly typed value 
    } 

 
    /// 
    /// Data structure for describing a property as a path below another
    /// 
    [TypeConverter(typeof(PropertyPathConverter))] 
    public sealed class PropertyPath
    { 
        //----------------------------------------------------- 
        //
        //  Constructors 
        //
        //-----------------------------------------------------

        ///  
        /// Construct a PropertyPath from a string and a list of parameters
        ///  
        public PropertyPath(string path, params object[] pathParameters) 
        {
            if (System.Windows.Threading.Dispatcher.CurrentDispatcher == null) 
                throw new InvalidOperationException();  // This is actually never called since CurrentDispatcher will throw if null.

            _path = path;
 
            if (pathParameters.Length > 0)
            { 
                // initialize internal pathParameters list 
                PathParameterCollection parameters = new PathParameterCollection(pathParameters);
                SetPathParameterCollection(parameters); 
            }
            PrepareSourceValueInfo(null);
        }
 
        /// 
        /// Public constructor that takes a single parameter.  This is 
        /// the degenerate PropertyPath (a path of a single step). 
        /// 
        public PropertyPath(object parameter) 
            : this(SingleStepPath, parameter)
        {
        }
 
        // This constructor is for use by the PropertyPathConverter
        internal PropertyPath(string path, ITypeDescriptorContext typeDescriptorContext) 
        { 
            _path = path;
            PrepareSourceValueInfo(typeDescriptorContext); 
            NormalizePath();
        }

        //------------------------------------------------------ 
        //
        //  Public properties 
        // 
        //-----------------------------------------------------
 
        ///  The string describing the path. 
        public string Path
        {
            get { return _path; } 
            set
            { 
                _path = value; 
                PrepareSourceValueInfo(null);
            } 
        }

        /// 
        /// The list of parameters to use when the 
        /// path refers to indexed parameters.
        /// Each parameter in the list should be a DependencyProperty, 
        /// a PropertyInfo, or a PropertyDescriptor. 
        /// 
        public Collection PathParameters 
        {
            get
            {
                if (_parameters == null) 
                {
                    SetPathParameterCollection(new PathParameterCollection()); 
                } 
                return _parameters;
            } 
        }

        //------------------------------------------------------
        // 
        //  Internal properties
        // 
        //------------------------------------------------------ 

        // the number of levels in the path 
        internal int Length { get { return _arySVI.Length; } }

        // the status of the PropertyPath
        internal PropertyPathStatus Status { get { return SingleWorker.Status; } } 

        // the most recent error message 
        internal string LastError { get { return _lastError; } } 

        // convenience properties for a frequent special case 
        internal object LastItem { get { return GetItem(Length - 1); } }
        internal object LastAccessor { get { return GetAccessor(Length - 1); } }
        internal object[] LastIndexerArguments { get { return GetIndexerArguments(Length - 1); } }
 
        //-----------------------------------------------------
        // 
        //  Internal methods 
        //
        //------------------------------------------------------ 

        // Convert an "accessor" into one of the legal types
        internal static void DowncastAccessor(object accessor,
                            out DependencyProperty dp, out PropertyInfo pi, out PropertyDescriptor pd) 
        {
            dp = accessor as DependencyProperty; 
 
            if (dp != null)
            { 
                pd = null;
                pi = null;
            }
            else 
            {
                pi = accessor as PropertyInfo; 
 
                if (pi != null)
                { 
                    pd = null;
                }
                else
                { 
                    pd = accessor as PropertyDescriptor;
                } 
            } 
        }
 
        // Set the context for the path.  Use this method in "target" mode
        // to connect the path to a rootItem for a short time:
        //      using (path.SetContext(myItem))
        //      { 
        //          ... call target-mode convenience methods ...
        //      } 
        internal IDisposable SetContext(object rootItem) 
        {
            return SingleWorker.SetContext(rootItem); 
        }

        // return the item for level k.  This is the result of evaluating the
        // path up to level k-1, starting at the root item. 
        internal object GetItem(int k)
        { 
            return SingleWorker.GetItem(k); 
        }
 
        // return the "accessor" for level k.  This is the object used to get
        // the value of level k (together with the level-k item).  It can be
        // a DP, a PropertyInfo, a PropertyDescriptor, etc.
        internal object GetAccessor(int k) 
        {
            object accessor = _earlyBoundPathParts[k]; 
 
            if (accessor == null)
            { 
                accessor = SingleWorker.GetAccessor(k);
            }

            return accessor; 
        }
 
        // return the arguments to use when the accessor at level k is an 
        // indexer.  (If it's not an indexer, this returns null.)
        internal object[] GetIndexerArguments(int k) 
        {
            return SingleWorker.GetIndexerArguments(k);
        }
 
        // return the value of the path.  Must be called within the scope
        // of SetContext. 
        internal object GetValue() 
        {
            return SingleWorker.RawValue(); 
        }

        // return the number of unresolved attached properties (called by Binding)
        internal int ComputeUnresolvedAttachedPropertiesInPath() 
        {
            // the path uses attached properties by the syntax (ClassName.PropName). 
            // If there are any such properties in the path, the binding needs the 
            // tree context to resolve the class name.
            int result = 0; 

            for (int k=Length-1; k>=0; --k)
            {
                if (_earlyBoundPathParts[k] == null) 
                {
                    string name = _arySVI[k].name; 
                    if (IsPropertyReference(name)) 
                    {
                        // a dot inside parens, when there's no early-bound accessor, 
                        // is an unresolved PD name
                        if (name.IndexOf('.') >= 0)
                            ++ result;
                    } 
                }
            } 
 
            return result;
        } 

        //-----------------------------------------------------
        //
        //  Internal properties and methods for use by PropertyPathWorker only 
        //
        //----------------------------------------------------- 
 
        internal SourceValueInfo[] SVI
        { 
            get
            {
                //Debug.Assert(Helper.IsCallerOfType(typeof(PropertyPathWorker)));
                return _arySVI; 
            }
        } 
 
        internal object ResolvePropertyName(int level, object item, Type ownerType, object context)
        { 
            //Debug.Assert(Helper.IsCallerOfType(typeof(PropertyPathWorker)));

            // if user told us explicitly what to use, use it
            object accessor = _earlyBoundPathParts[level]; 

            if (accessor == null) 
            { 
                // strip away enclosing () and resolve the name
                string name = _arySVI[level].name; 
                if (IsPropertyReference(name))
                    name = name.Substring(1, name.Length - 2);

                accessor = ResolvePropertyName(name, item, ownerType, context, false); 
            }
 
            return accessor; 
        }
 
        internal IndexerParameterInfo[] ResolveIndexerParams(int level, object context)
        {
            IndexerParameterInfo[] parameters = _earlyBoundPathParts[level] as IndexerParameterInfo[];
 
            if (parameters == null)
            { 
                parameters = ResolveIndexerParams(_arySVI[level].paramList, context, false); 
            }
 
            return parameters;
        }

        // PropertyPathWorker may choose to replace an indexer by a property 
        internal void ReplaceIndexerByProperty(int level, string name)
        { 
            _arySVI[level].name = name; 
            _arySVI[level].propertyName = name;
            _arySVI[level].type = SourceValueType.Property; 

            _earlyBoundPathParts[level] = null;
        }
 
        //-----------------------------------------------------
        // 
        //  Private properties 
        //
        //------------------------------------------------------ 

        PropertyPathWorker SingleWorker
        {
            get 
            {
                if (_singleWorker == null) 
                    _singleWorker = new PropertyPathWorker(this); 
                return _singleWorker;
            } 
        }

        //-----------------------------------------------------
        // 
        //  Private methods
        // 
        //------------------------------------------------------ 

        // parse the path to figure out what kind of 
        // SourceValueInfo we're going to need
        private void PrepareSourceValueInfo(ITypeDescriptorContext typeDescriptorContext)
        {
            PathParser parser = DataBindEngine.CurrentDataBindEngine.PathParser; 
            _arySVI = parser.Parse(Path);
 
            if (_arySVI.Length == 0) 
            {
                string detail = parser.Error; 
                if (detail == null)
                    detail = Path;
                throw new InvalidOperationException(SR.Get(SRID.PropertyPathSyntaxError, detail));
            } 

            ResolvePathParts(typeDescriptorContext); 
        } 

        // "normalize" the path - i.e. load the PathParameters with the early-bound 
        // accessors, and replace the corresponding parts of the path with
        // parameter references
        private void NormalizePath()
        { 
            StringBuilder builder = new StringBuilder();
            PathParameterCollection parameters = new PathParameterCollection(); 
 
            for (int i=0; i<_arySVI.Length; ++i)
            { 
                switch (_arySVI[i].drillIn)
                {
                    case DrillIn.Always:
                        builder.Append('/'); 
                        break;
 
                    case DrillIn.Never: 
                        builder.Append('.');
                        break; 

                    case DrillIn.IfNeeded:
                        break;
                } 

                switch (_arySVI[i].type) 
                { 
                    case SourceValueType.Property:
                        if (_earlyBoundPathParts[i] != null) 
                        {
                            builder.Append('(');
                            builder.Append(parameters.Count.ToString(DataBindEngine.EnglishUSCulture.NumberFormat));
                            builder.Append(')'); 

                            parameters.Add(_earlyBoundPathParts[i]); 
                        } 
                        else
                        { 
                            builder.Append(_arySVI[i].name);
                        }
                        break;
 
                    case SourceValueType.Indexer:
                        builder.Append('['); 
                        if (_earlyBoundPathParts[i] != null) 
                        {
                            IndexerParameterInfo[] aryIPI = (IndexerParameterInfo[])_earlyBoundPathParts[i]; 
                            // the params should be at the very least a single empty string
                            Debug.Assert(aryIPI.Length > 0);
                            int j = 0;
                            while (true) 
                            {
                                IndexerParameterInfo info = aryIPI[j]; 
                                if (info.type != null) 
                                {
                                    builder.Append('('); 
                                    builder.Append(parameters.Count.ToString(DataBindEngine.EnglishUSCulture.NumberFormat));
                                    builder.Append(')');

                                    parameters.Add(info.value); 
                                }
                                else 
                                { 
                                    builder.Append(info.value);
                                } 
                                ++j;

                                if (j < aryIPI.Length)
                                { 
                                    builder.Append(',');
                                } 
                                else 
                                {
                                    break; 
                                }
                            }
                        }
                        else 
                        {
                            builder.Append(_arySVI[i].name); 
                        } 
                        builder.Append(']');
                        break; 

                    case SourceValueType.Direct:
                        break;
                } 

            } 
 
            if (parameters.Count > 0)
            { 
                _path = builder.ToString();
                SetPathParameterCollection(parameters);
            }
        } 

        // set new parameter collection; update collection change notification handler 
        private void SetPathParameterCollection(PathParameterCollection parameters) 
        {
            if (_parameters != null) 
            {
                _parameters.CollectionChanged -= new NotifyCollectionChangedEventHandler(ParameterCollectionChanged);
            }
            _parameters = parameters; 
            if (_parameters != null)
            { 
                _parameters.CollectionChanged += new NotifyCollectionChangedEventHandler(ParameterCollectionChanged); 
            }
        } 

        // path parameters were added/removed, update SourceValueInfo
        private void ParameterCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        { 
            PrepareSourceValueInfo(null);
        } 
 

        // resolve the property names and path parameters early, if possible 
        void ResolvePathParts(ITypeDescriptorContext typeDescriptorContext)
        {
            bool throwOnError = (typeDescriptorContext != null);
 
            object context = null;
 
            TypeConvertContext typeConvertContext = typeDescriptorContext as TypeConvertContext; 
            if( typeConvertContext != null )
                context = typeConvertContext.ParserContext; 

            if (context == null)
                context = typeDescriptorContext;
            _earlyBoundPathParts = new object[Length]; 

            for (int level=Length-1; level>=0; --level) 
            { 
                if (_arySVI[level].type == SourceValueType.Property)
                { 
                    string name = _arySVI[level].name;
                    if (IsPropertyReference(name))
                    {
                        object accessor = ResolvePropertyName(name.Substring(1, name.Length-2), null, null, context, throwOnError); 
                        _earlyBoundPathParts[level] = accessor;
 
                        if (accessor != null) 
                        {
                            _arySVI[level].propertyName = GetPropertyName(accessor); 
                        }
                    }
                    else
                    { 
                        _arySVI[level].propertyName = name;
                    } 
                } 
                else if (_arySVI[level].type == SourceValueType.Indexer)
                { 
                    IndexerParameterInfo[] indexerParams = ResolveIndexerParams(_arySVI[level].paramList, context, throwOnError);
                    _earlyBoundPathParts[level] = indexerParams;
                    _arySVI[level].propertyName = Binding.IndexerName;
                } 
            }
        } 
 
        // resolve a single DP name
        object ResolvePropertyName(string name, object item, Type ownerType, object context, bool throwOnError) 
        {
            string propertyName;
            int lastIndex = name.LastIndexOf('.');
 
            if (lastIndex == -1)
            { 
                // simple name - first see if it is an index into the parameter list 
                int index;
                if (IsParameterIndex(name, false, out index)) 
                {
                    if (0 <= index && index < PathParameters.Count)
                    {
                        object accessor = PathParameters[index]; 
                        // always throw if the accessor isn't valid - this error cannot
                        // be corrected later on. 
                        if (!IsValidAccessor(accessor)) 
                            throw new InvalidOperationException(SR.Get(SRID.PropertyPathInvalidAccessor,
                                        (accessor != null) ? accessor.GetType().FullName : "null")); 

                        return accessor;
                    }
                    else if (throwOnError) 
                        throw new InvalidOperationException(SR.Get(SRID.PathParametersIndexOutOfRange, index, PathParameters.Count));
                    else return null; 
                } 

                // otherwise look for the name on the owner type (below) 
                propertyName = name;
            }
            else
            { 
                // attached property - get the owner type
                propertyName = name.Substring(lastIndex + 1).Trim(); 
                string ownerName = name.Substring(0, lastIndex).Trim(); 
                ownerType = GetTypeFromName(ownerName, context);
                if (ownerType == null && throwOnError) 
                    throw new InvalidOperationException(SR.Get(SRID.PropertyPathNoOwnerType, ownerName));
            }

            if (ownerType != null) 
            {
                // get an appropriate accessor from the ownerType and propertyName. 
                // We prefer accessors in a certain order, defined below. 
                object accessor;
 
                // 1. DependencyProperty on the given type.
                accessor = DependencyProperty.FromName(propertyName, ownerType);

                // 2. PropertyDescriptor from item's custom lookup. 
                // When the item implements custom properties, we must use them.
                if (accessor == null && item is ICustomTypeDescriptor) 
                { 
                    accessor = TypeDescriptor.GetProperties(item)[propertyName];
                } 

                // 3a. PropertyInfo, when item exposes INotifyPropertyChanged.
                // 3b. PropertyInfo, when item is a DependencyObject (bug 1373351).
                // This uses less working set than PropertyDescriptor, and we don't need 
                // the ValueChanged pattern.  (If item is a DO and wants to raise
                // change notifications, it should make the property a DP.) 
                if (accessor == null && 
                    (item is INotifyPropertyChanged || item is DependencyObject))
                { 
                    accessor = ownerType.GetProperty(propertyName);
                }

                // 4. PropertyDescriptor (obtain from item - this is reputedly 
                // slower than obtaining from type, but the latter doesn't
                // discover properties obtained from TypeDescriptorProvider - 
                // see bug 1713000). 
                // This supports the WinForms ValueChanged pattern.
                if (accessor == null) 
                {
                    accessor = TypeDescriptor.GetProperties(item)[propertyName];
                }
 
                // 5. PropertyInfo.
                // This will probably never happen, as the previous case subsumes it. 
                if (accessor == null) 
                {
                    accessor = ownerType.GetProperty(propertyName); 
                }

                if (accessor == null && throwOnError)
                    throw new InvalidOperationException(SR.Get(SRID.PropertyPathNoProperty, ownerType.Name, propertyName)); 

                return accessor; 
            } 

            return null; 
        }

        // resolve indexer parameters
        IndexerParameterInfo[] ResolveIndexerParams(FrugalObjectList paramList, object context, bool throwOnError) 
        {
            IndexerParameterInfo[] args = new IndexerParameterInfo[paramList.Count]; 
            for (int i = 0; i < args.Length; ++i) 
            {
                if (String.IsNullOrEmpty(paramList[i].parenString)) 
                {
                    // no paren string "foo" - value is (uninterpreted) value string
                    args[i].value = paramList[i].valueString;
                } 
                else if (String.IsNullOrEmpty(paramList[i].valueString))
                { 
                    // no value string "(2)" - value comes from PathParameter list 
                    int index;
                    if (Int32.TryParse( paramList[i].parenString.Trim(), 
                                        NumberStyles.Integer,
                                        DataBindEngine.EnglishUSCulture.NumberFormat,
                                        out index))
                    { 
                        if (0 <= index && index < PathParameters.Count)
                        { 
                            object value = PathParameters[index]; 
                            if (value != null)
                            { 
                                args[i].value = value;
                                args[i].type = value.GetType();
                            }
                            else if (throwOnError) 
                            {
                                // info.value will still be "(n)" 
                                throw new InvalidOperationException(SR.Get(SRID.PathParameterIsNull, index)); 
                            }
                        } 
                        else if (throwOnError)
                            throw new InvalidOperationException(SR.Get(SRID.PathParametersIndexOutOfRange, index, PathParameters.Count));
                    }
                    else 
                    {
                        // parens didn't hold an integer "(abc)" - value is (uninterpreted) paren string 
                        // [this could be considered an error, but the original code 
                        // treated it like this, so to preserve compatibility...]
                        args[i].value = "(" + paramList[i].parenString + ")"; 
                    }
                }
                else
                { 
                    // both strings appear "(Double)3.14159" - value is type-converted from value string
                    args[i].type = GetTypeFromName(paramList[i].parenString, context); 
                    if (args[i].type != null) 
                    {
                        object value = GetTypedParamValue(paramList[i].valueString.Trim(), args[i].type, throwOnError); 
                        if (value != null)
                        {
                            args[i].value = value;
                        } 
                        else
                        { 
                            if (throwOnError) 
                                throw new InvalidOperationException(SR.Get(SRID.PropertyPathIndexWrongType, paramList[i].parenString, paramList[i].valueString));
                            args[i].type = null; 
                        }
                    }
                    else
                    { 
                        // parens didn't hold a type name "(abc)xyz" - value is (uninterpreted) string
                        // [this could be considered an error, but the original code 
                        // treated it like this, so to preserve compatibility...] 
                        args[i].value = "(" + paramList[i].parenString + ")" + paramList[i].valueString;
                    } 
                }
            }
            return args;
        } 

        object GetTypedParamValue(string param, Type type, bool throwOnError) 
        { 
            object value = null;
            if (type == typeof(string)) 
                return param;

            TypeConverter tc = TypeDescriptor.GetConverter(type);
 
            if (tc != null && tc.CanConvertFrom(typeof(string)))
            { 
                // PreSharp uses message numbers that the C# compiler doesn't know about. 
                // Disable the C# complaints, per the PreSharp documentation.
                #pragma warning disable 1634, 1691 

                // PreSharp complains about catching NullReference (and other) exceptions.
                // It doesn't recognize that IsCriticalException() handles these correctly.
                #pragma warning disable 56500 

                try 
                { 
                    value = tc.ConvertFromString(null, CultureInfo.InvariantCulture,
                                                    param); 
                    // technically the converter can return null as a legitimate
                    // value.  In practice, this seems always to be a sign that
                    // the conversion didn't work (often because the converter
                    // reverts to the default behavior - returning null).  So 
                    // we treat null as an "error", and keep trying for something
                    // better.  (See bug 861966) 
                } 
                // catch all exceptions.  We simply want to move on to the next
                // candidate indexer. 
                catch (Exception ex)
                {
                    if (CriticalExceptions.IsCriticalException(ex) || throwOnError)
                        throw; 
                }
                catch 
                { 
                    if (throwOnError)
                        throw; 
                }

                #pragma warning restore 56500
                #pragma warning restore 1634, 1691 
            }
 
            if (value == null && type.IsAssignableFrom(typeof(string))) 
            {
                value = param; 
            }
            return value;
        }
 

        // Return the type named by the given name 
        Type GetTypeFromName(string name, object context) 
        {
            // use the parser context, if available.  This allows early resolution. 
            ParserContext parserContext = context as ParserContext;
            if (parserContext != null)
            {
                // Find the namespace prefix 
                string nsPrefix;
                int nsIndex = name.IndexOf(':'); 
                if (nsIndex == -1) 
                    nsPrefix = string.Empty;
                else 
                {
                    // Found a namespace prefix separator, so create replacement _pathString.
                    // String processing - split "foons" from "BarClass.BazProp"
                    nsPrefix = name.Substring(0, nsIndex).TrimEnd(); 
                    name = name.Substring(nsIndex + 1).TrimStart();
                } 
 
                // Find the namespace URI, even if its the default one
                string namespaceURI = parserContext.XmlnsDictionary[nsPrefix]; 
                if (namespaceURI == null)
                {
                    throw new ArgumentException(SR.Get(SRID.ParserPrefixNSProperty, nsPrefix, name));
                } 

                TypeAndSerializer typeAndSerializer = parserContext.XamlTypeMapper.GetTypeOnly(namespaceURI, name); 
 
                return (typeAndSerializer != null) ? typeAndSerializer.ObjectType : null;
            } 

            else
            {
                IValueSerializerContext serializerContext = context as IValueSerializerContext; 
                if (serializerContext != null)
                { 
                    ValueSerializer typeSerializer = ValueSerializer.GetSerializerFor(typeof(Type), serializerContext); 
                    if (typeSerializer != null)
                        return typeSerializer.ConvertFromString(name, serializerContext) as Type; 
                }
            }

            // if there's no parser or serializer context, use the tree context 
            DependencyObject hostElement = context as DependencyObject;
            if (hostElement != null) 
            { 
                return XamlTypeMapper.GetTypeFromName(name, hostElement);
            } 

            // if there's no context of any kind, give up
            return null;
        } 

        // return true if the name has the form:  (property) 
        internal static bool IsPropertyReference(string name) 
        {
            return (name != null && name.Length > 1 && name[0] == '(' && (name[name.Length - 1] == ')')); 
        }

        // return true if the name has the form:  (nnn)
        internal static bool IsParameterIndex(string name, bool stripParens, out int index) 
        {
            if (stripParens) 
            { 
                if (IsPropertyReference(name))
                { 
                    name = name.Substring(1, name.Length - 2);
                }
                else
                { 
                    index = -1;
                    return false; 
                } 
            }
 
            return Int32.TryParse( name,
                                NumberStyles.Integer,
                                DataBindEngine.EnglishUSCulture.NumberFormat,
                                out index); 
        }
 
        // determine if an object is one of the accessors we support 
        static bool IsValidAccessor(object accessor)
        { 
            return  accessor is DependencyProperty ||
                    accessor is PropertyInfo  ||
                    accessor is PropertyDescriptor;
        } 

        // determine the name of an accessor 
        static string GetPropertyName(object accessor) 
        {
            DependencyProperty dp; 
            PropertyInfo pi;
            PropertyDescriptor pd;

            if ((dp = accessor as DependencyProperty) != null) 
                return dp.Name;
            else if ((pi = accessor as PropertyInfo) != null) 
                return pi.Name; 
            else if ((pd = accessor as PropertyDescriptor) != null)
                return pd.Name; 
            else
            {
                Invariant.Assert(false, "Unknown accessor type");
                return null; 
            }
        } 
 
        //------------------------------------------------------
        // 
        //  Private Enums, Structs, Constants
        //
        //-----------------------------------------------------
 
        const string SingleStepPath = "(0)";
        static readonly Char[] s_comma = new Char[]{','}; 
 
        //------------------------------------------------------
        // 
        //  Private data
        //
        //-----------------------------------------------------
 
        string _path = String.Empty;        // the path
        PathParameterCollection _parameters; // list of DPs to inject into the path 
 
        SourceValueInfo[] _arySVI;          // static description of each level in the path
        string _lastError = String.Empty;   // most recent error message 
        object[] _earlyBoundPathParts;      // accessors and indexer parameters that got resolved early
        PropertyPathWorker _singleWorker;   // shared worker - used in "target" mode

        //----------------------------------------------------- 
        //
        //  Private types 
        // 
        //-----------------------------------------------------
        private class PathParameterCollection : ObservableCollection 
        {
            public PathParameterCollection()
            {
            } 

            public PathParameterCollection(object[] parameters) 
            { 
                IList items = Items;
                foreach (object o in parameters) 
                {
                    items.Add(o);
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK