File: System\Windows\Markup\RoutedEventConverter.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Xaml;
using System.ComponentModel;
using System.Globalization;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
 
namespace System.Windows.Markup
{
    /// <summary>
    ///     Type converter for RoutedEvent type
    /// </summary>
    public sealed class RoutedEventConverter : TypeConverter
    {
        /// <summary>
        ///     Whether we can convert from a given type - this class only converts from string
        /// </summary>
        public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType)
        {
            // We can only convert from a string and that too only if we have all the contextual information
            // Note: Sometimes even the serializer calls CanConvertFrom in order 
            // to determine if it is a valid converter to use for serialization.
            if (sourceType == typeof(string))
            {
                return true;
            }
 
            return false;
        }
 
        /// <summary>
        ///     Whether we can convert to a given type - this class only converts to string
        /// </summary>
        public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType)
        {
            return false;
        }
 
        /// <summary>
        ///     Convert a string like "Button.Click" into the corresponding RoutedEvent
        /// </summary>
        public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext,
                                           CultureInfo cultureInfo,
                                           object source)
        {
            string routedEventName = source as string;
            RoutedEvent routedEvent = null;
 
            if (routedEventName != null)
            {
                routedEventName = routedEventName.Trim();
                IServiceProvider serviceProvider = typeDescriptorContext as IServiceProvider;
 
                if (serviceProvider != null)
                {
                    IXamlTypeResolver resolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
                    Type type = null;
 
                    if (resolver != null)
                    {
                        // Verify that there's at least one period.  (A simple
                        //  but not foolproof check for "[class].[event]")
                        int lastIndex = routedEventName.IndexOf('.');
                        if (lastIndex != -1)
                        {
                            string typeName = routedEventName.Substring(0, lastIndex);
                            routedEventName = routedEventName.Substring(lastIndex + 1);
 
                            type = resolver.Resolve(typeName);  
                        }
                    }
 
                    if (type == null)
                    {              
                        IXamlSchemaContextProvider schemaContextProvider = (typeDescriptorContext.
                            GetService(typeof(IXamlSchemaContextProvider))
                                as IXamlSchemaContextProvider);
 
                        IAmbientProvider iapp = serviceProvider.GetService(typeof(IAmbientProvider)) as IAmbientProvider;
 
                        if (schemaContextProvider != null && iapp != null)
                        {
                            XamlSchemaContext schemaContext = schemaContextProvider.SchemaContext;
 
                            XamlType styleXType = schemaContext.GetXamlType(typeof(Style));
 
                            List<XamlType> ceilingTypes = new List<XamlType>();
                            ceilingTypes.Add(styleXType);
 
                            XamlMember styleTargetType = styleXType.GetMember("TargetType");
 
                            AmbientPropertyValue firstAmbientValue = iapp.GetFirstAmbientValue(ceilingTypes, styleTargetType);
 
                            if (firstAmbientValue != null)
                            {
                                type = firstAmbientValue.Value as Type;
                            }
                            if (type == null)
                            {
                                type = typeof(FrameworkElement);
                            }
                        }
                    }
 
                    if (type != null)
                    {
                        Type currentType = type;
 
                        // Force load the Statics by walking up the hierarchy and running class constructors
                        while (null != currentType)
                        {
                            RuntimeHelpers.RunClassConstructor(currentType.TypeHandle);
                            currentType = currentType.BaseType;
                        }
 
                        routedEvent = EventManager.GetRoutedEventFromName(routedEventName, type);
                    }
                }
            }
 
            if (routedEvent == null)
            {
                // Falling through here means we are unable to perform the conversion.
                throw GetConvertFromException(source);
            }
 
            return routedEvent;
        }
 
        /// <summary>
        ///     Convert a RoutedEventID into a XAML string like "Button.Click"
        /// </summary>
        public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext,
                                         CultureInfo cultureInfo,
                                         object value,
                                         Type destinationType)
        {
            ArgumentNullException.ThrowIfNull(value);
            ArgumentNullException.ThrowIfNull(destinationType);
 
            throw GetConvertToException(value, destinationType);
        }
 
        // This routine is copied from TemplateBamlRecordReader.  This functionality
        //  is planned to be part of the utilities exposed by the parser, eliminating
        //  the need to duplicate code.  See task #18279
        private string ExtractNamespaceString(ref string nameString, ParserContext parserContext)
        {
            // The colon is what we look for to determine if there's a namespace prefix specifier.
            int nsIndex = nameString.IndexOf(':');
            string nsPrefix = string.Empty;
            if (nsIndex != -1)
            {
                // Found a namespace prefix separator, so create replacement propertyName.
                // String processing - split "foons" from "BarClass.BazProp"
                nsPrefix = nameString.Substring(0, nsIndex);
                nameString = nameString.Substring(nsIndex + 1);
            }
 
            // Find the namespace, even if its the default one
            string namespaceURI = parserContext.XmlnsDictionary[nsPrefix];
            if (namespaceURI == null)
            {
                throw new ArgumentException(SR.Format(SR.ParserPrefixNSProperty, nsPrefix, nameString));
            }
 
            return namespaceURI;
        }
    }
}