XamlUsageSyntax.cs :  » Development » Sandcastle » Microsoft » Ddue » Tools » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » Sandcastle 
Sandcastle » Microsoft » Ddue » Tools » XamlUsageSyntax.cs
// Copyright  Microsoft Corporation.
// This source file is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Xml.XPath;
using System.Configuration;
using System.IO;

namespace Microsoft.Ddue.Tools{
    public class XamlUsageSyntaxGenerator : SyntaxGeneratorTemplate
    {

        public XamlUsageSyntaxGenerator(XPathNavigator configuration)
            : base(configuration)
        {
            LoadConfigNode(configuration);
            if (String.IsNullOrEmpty(Language)) Language = "XAML";
        }

        public override void WriteSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            writer.WriteStartBlock(Language);

            // Check the list of assemblies for which to generate XAML syntax
            string assemblyName = (string)reflection.Evaluate(apiContainingAssemblyExpression);
            string namespaceName = (string)reflection.Evaluate(apiContainingNamespaceNameExpression);
            if (!xamlAssemblies.ContainsKey(assemblyName.ToLower()))
            {
                WriteXamlBoilerplate(XamlBoilerplateID.nonXamlAssemblyBoilerplate, writer);
            }
            else
            {
                string group = (string)reflection.Evaluate(apiGroupExpression);
                switch (group)
                {
                    case "namespace":
                        WriteNamespaceSyntax(reflection, writer);
                        break;
                    case "type":
                        WriteTypeSyntax(reflection, writer);
                        break;
                    case "member":
                        WriteMemberSyntax(reflection, writer);
                        break;
                }
                WriteXamlXmlnsUri(assemblyName, namespaceName, writer);
            }

            writer.WriteEndBlock();
        }
        
        private void WriteXamlXmlnsUri(string assemblyName, string namespaceName, SyntaxWriter writer)
        {
            Dictionary<string, List<string>> clrNamespaces;
            if (xamlAssemblies.TryGetValue(assemblyName.ToLower(), out clrNamespaces))
            {
                List<string> xmlnsUriList;
                if (clrNamespaces.TryGetValue(namespaceName, out xmlnsUriList))
                {
                    foreach (string xmlnsUri in xmlnsUriList)
                    {
                        // start the syntax block
                        writer.WriteStartSubBlock("xamlXmlnsUri");
                        writer.WriteString(xmlnsUri);
                        writer.WriteEndSubBlock();
                    }
                }
            }
        }

        // list of classes whose subclasses do NOT get XAML syntax
        protected List<string> excludedAncestorList = new List<string>();

        // list of assemblies whose members get XAML syntax
        // the nested Dictionary is a list of assembly's namespaces that have one or more xmlns uris for xaml
        private Dictionary<string, Dictionary<string, List<string>>> xamlAssemblies = new Dictionary<string, Dictionary<string, List<string>>>();


        private void LoadConfigNode(XPathNavigator configuration)
        {
            // get the filter files
            XPathNodeIterator filterNodes = configuration.Select("filter");
            if (filterNodes.Count == 0)
            {
                LoadConfiguration(configuration);
                return;
            }

            foreach (XPathNavigator filterNode in filterNodes)
            {
                string filterFiles = filterNode.GetAttribute("files", String.Empty);
                if ((filterFiles == null) || (filterFiles.Length == 0))
                    throw new ConfigurationErrorsException("The XamlUsageSyntaxGenerator filter/@files attribute must specify a path.");
                ParseDocuments(filterFiles);
            }
        }

        private void LoadConfiguration(XPathNavigator configuration)
        {
            // get the list of excluded ancestor classes
            foreach (XPathNavigator excludedClass in configuration.Select("xamlExcludedAncestors/class"))
            {
                string apiId = excludedClass.GetAttribute("api", string.Empty);
                if (apiId.Length > 0 && !excludedAncestorList.Contains(apiId))
                    excludedAncestorList.Add(apiId);
            }

            // get the list of XAML assemblies; members in other assemblies get no xaml syntax, just 'not applicable' boilerplate
            foreach (XPathNavigator xamlAssembly in configuration.Select("xamlAssemblies/assembly"))
            {
                string assemblyName = xamlAssembly.GetAttribute("name", string.Empty);
                if (string.IsNullOrEmpty(assemblyName))
                    continue; // should emit warning message

                Dictionary<string, List<string>> clrNamespaces;
                if (!xamlAssemblies.TryGetValue(assemblyName.ToLower(), out clrNamespaces))
                {
                    clrNamespaces = new Dictionary<string, List<string>>();
                    xamlAssemblies.Add(assemblyName.ToLower(), clrNamespaces);
                }

                foreach (XPathNavigator xmlnsNode in xamlAssembly.Select("xmlns[@uri][clrNamespace]"))
                {
                    string xmlnsUri = xmlnsNode.GetAttribute("uri", string.Empty);
                    if (string.IsNullOrEmpty(xmlnsUri))
                        continue; // should emit warning message

                    foreach (XPathNavigator clrNamespaceNode in xmlnsNode.Select("clrNamespace[@name]"))
                    {
                        string namespaceName = clrNamespaceNode.GetAttribute("name", string.Empty);
                        if (string.IsNullOrEmpty(namespaceName))
                            continue; // should emit warning message

                        List<string> xmlnsUriList;
                        if (!clrNamespaces.TryGetValue(namespaceName, out xmlnsUriList))
                        {
                            xmlnsUriList = new List<string>();
                            clrNamespaces.Add(namespaceName, xmlnsUriList);
                        }
                        if (!xmlnsUriList.Contains(xmlnsUri))
                            xmlnsUriList.Add(xmlnsUri);
                    }
                }
            }
        }

        public void ParseDocuments(string wildcardPath)
        {
            string filterFiles = Environment.ExpandEnvironmentVariables(wildcardPath);
            if ((filterFiles == null) || (filterFiles.Length == 0))
                throw new ConfigurationErrorsException("The XamlUsageSyntaxGenerator filter path is an empty string.");

            //WriteMessage(MessageLevel.Info, String.Format("XamlUsageSyntaxGenerator: Searching for files that match '{0}'.", filterFiles));
            string directoryPart = Path.GetDirectoryName(filterFiles);
            if (String.IsNullOrEmpty(directoryPart))
                directoryPart = Environment.CurrentDirectory;
            directoryPart = Path.GetFullPath(directoryPart);
            string filePart = Path.GetFileName(filterFiles);
            string[] files = Directory.GetFiles(directoryPart, filePart);
            foreach (string file in files)
                ParseDocument(file);
            //WriteMessage(MessageLevel.Info, String.Format("Found {0} files in {1}.", files.Length, filterFiles));
        }

        private void ParseDocument(string file)
        {
            try
            {
                XPathDocument document = new XPathDocument(file);

                XPathNavigator xamlSyntaxNode = document.CreateNavigator().SelectSingleNode("/*");
                LoadConfiguration(xamlSyntaxNode);
            }
            catch (Exception e)
            {
                throw new ConfigurationErrorsException(string.Format("Exception parsing XamlUsageSyntaxGenerator filter file: {0}. Exception message: {1}", file, e.Message));
            }
        }

        public override void WriteNamespaceSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            // empty xaml syntax for namespace topics
        }

        private void WriteXamlBoilerplate(XamlBoilerplateID bpID, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(bpID, null, writer);
        }

        private void WriteXamlBoilerplate(XamlBoilerplateID bpID, XPathNavigator typeReflection, SyntaxWriter writer)
        {
            string xamlBlockId = System.Enum.GetName(typeof(XamlBoilerplateID), bpID);
            if (xamlBlockId != null)
            {
                writer.WriteStartSubBlock(xamlBlockId);
                if (typeReflection != null)
                    WriteTypeReference(typeReflection, writer);
                writer.WriteEndSubBlock();
            }
        }

        public override void WriteClassSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            string name = reflection.Evaluate(apiNameExpression).ToString();
            bool isAbstract = (bool)reflection.Evaluate(apiIsAbstractTypeExpression);
            bool isSealed = (bool)reflection.Evaluate(apiIsSealedTypeExpression);
            bool isSerializable = (bool)reflection.Evaluate(apiIsSerializableTypeExpression);
            // 
            if (isAbstract && !isSealed)
            {
                // Output boilerplate for abstract class 
                WriteXamlBoilerplate(XamlBoilerplateID.classXamlSyntax_abstract, writer);
            }
            else if (!HasDefaultConstructor(reflection))
            {
                if (HasTypeConverterAttribute(reflection))
                {
                    WriteXamlBoilerplate(XamlBoilerplateID.classXamlSyntax_noDefaultCtorWithTypeConverter, writer);
                }
                else
                {
                    WriteXamlBoilerplate(XamlBoilerplateID.classXamlSyntax_noDefaultCtor, writer);
                }
            }
            else if (IsExcludedSubClass(reflection))
            {
                WriteXamlBoilerplate(XamlBoilerplateID.classXamlSyntax_excludedSubClass, writer);
            }
            else
            {
                // show the default XAML syntax for classes
                // Note: skipped the test for TypeConverterAttribute shown in the flowchart because same syntax either way
                ObjectElementUsageForClassStruct(reflection, writer);
            }
        }

        private void ObjectElementUsageForClassStruct(XPathNavigator reflection, SyntaxWriter writer)
        {
            string typeName = (string)reflection.Evaluate(apiNameExpression);
            bool isGeneric = (bool)reflection.Evaluate(apiIsGenericExpression);
            string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlObjectElementUsageHeading);

            string contentPropertyId = (string)reflection.Evaluate(contentPropertyIdExpression);
            if (contentPropertyId == "")
                contentPropertyId = (string)reflection.Evaluate(ancestorContentPropertyIdExpression);

            // start the syntax block
            writer.WriteStartSubBlock(xamlBlockId);

            writer.WriteString("<");
            if (isGeneric)
            {
                writer.WriteIdentifier(typeName);

                // for generic types show the type arguments
                XPathNodeIterator templates = (XPathNodeIterator)reflection.Evaluate(apiTemplatesExpression);
                if (templates.Count > 0)
                {
                    writer.WriteString(" x:TypeArguments=\"");
                    while (templates.MoveNext())
                    {
                        XPathNavigator template = templates.Current;
                        string name = template.GetAttribute("name", String.Empty);
                        writer.WriteString(name);
                        if (templates.CurrentPosition < templates.Count)
                            writer.WriteString(",");
                    }
                    writer.WriteString("\"");
                }
            }
            else
            {
                // for non-generic types just show the name
                writer.WriteIdentifier(typeName);
            }
            if (contentPropertyId == string.Empty)
            {
                writer.WriteString(" .../>");
            }
            else
            {
                // close the start tag
                writer.WriteString(">");

                // the inner xml of the Object Element syntax for a type with a content property
                // is a link to the content property
                writer.WriteLine();
                writer.WriteString("  ");
                writer.WriteReferenceLink(contentPropertyId);
                writer.WriteLine();

                // write the end tag
                writer.WriteString("</");
                writer.WriteIdentifier(typeName);
                writer.WriteString(">");
            }

            // end the sub block
            writer.WriteEndSubBlock();
        }


        public override void WriteStructureSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            string name = (string)reflection.Evaluate(apiNameExpression);
            bool notWriteable = (bool)reflection.Evaluate(noSettablePropertiesExpression);

            if (notWriteable)
            {
                // Output boilerplate for struct with no writeable properties 
                WriteXamlBoilerplate(XamlBoilerplateID.structXamlSyntax_nonXaml, writer);
            }
            else
            {
                // All writeable structs in XAML assemblies are usable in XAML
                // always show the Object Element Usage syntax
                ObjectElementUsageForClassStruct(reflection, writer);

                // For structs with TypeConverterAttribute,
                // if we can show multiple syntax blocks, also output AttributeUsage boilerplate
                if (HasTypeConverterAttribute(reflection))
                    WriteXamlBoilerplate(XamlBoilerplateID.structXamlSyntax_attributeUsage, writer);
            }
        }

        public override void WriteInterfaceSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(XamlBoilerplateID.interfaceOverviewXamlSyntax, writer);
        }

        public override void WriteDelegateSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(XamlBoilerplateID.delegateOverviewXamlSyntax, writer);
        }

        public override void WriteEnumerationSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(XamlBoilerplateID.enumerationOverviewXamlSyntax, writer);
        }

        public override void WriteConstructorSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(XamlBoilerplateID.constructorOverviewXamlSyntax, writer);
        }

        public override void WriteMethodSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(XamlBoilerplateID.methodOverviewXamlSyntax, writer);
        }

        public override void WriteAttachedPropertySyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            string propertyName = (string)reflection.Evaluate(apiNameExpression);
            string containingTypeName = (string)reflection.Evaluate(apiContainingTypeNameExpression);
            bool isSettable = (bool)reflection.Evaluate(apiIsWritePropertyExpression);
            XPathNavigator returnType = reflection.SelectSingleNode(apiReturnTypeExpression);
            if (!isSettable)
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_readOnly, writer);
            }
            else
            {
                // xaml syntax block for attached property
                string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlAttributeUsageHeading);
                writer.WriteStartSubBlock(xamlBlockId);
                writer.WriteString("<");
                writer.WriteParameter("object");
                writer.WriteString(" ");
                writer.WriteIdentifier(containingTypeName + "." + propertyName);
                writer.WriteString("=\"");
                WriteTypeReference(returnType, writer);
                writer.WriteString("\" .../>");
                writer.WriteEndSubBlock();
            }
        }

        public override void WritePropertySyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            //containingTypeSubgroupExpression
            string propertyName = (string)reflection.Evaluate(apiNameExpression);
            bool isSettable = (bool)reflection.Evaluate(apiIsWritePropertyExpression);
            bool isSetterPublic = (bool)reflection.Evaluate(apiIsSetterPublicExpression);
            bool isAbstract = (bool)reflection.Evaluate(apiIsAbstractProcedureExpression);
            string propertyVisibility = (string)reflection.Evaluate(apiVisibilityExpression);
            XPathNodeIterator parameters = reflection.Select(apiParametersExpression);

            XPathNavigator returnType = reflection.SelectSingleNode(apiReturnTypeExpression);
            bool notWriteableReturnType = (bool)returnType.Evaluate(noSettablePropertiesExpression);
            string returnTypeId = returnType.GetAttribute("api", string.Empty);
            string returnTypeSubgroup = (string)returnType.Evaluate(apiSubgroupExpression);
            bool returnTypeIsAbstract = (bool)returnType.Evaluate(apiIsAbstractTypeExpression);
            bool returnTypeIsReadonlyStruct = (returnTypeSubgroup == "structure" && notWriteableReturnType && !IsPrimitiveType(returnTypeId));

            XPathNavigator containingType = reflection.SelectSingleNode(apiContainingTypeExpression);
            string containingTypeSubgroup = (string)containingType.Evaluate(apiSubgroupExpression);

            // an ordinary property, not an attached prop
            if (containingTypeSubgroup == "interface")
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_noXamlSyntaxForInterfaceMembers, writer);
            }
            else if ((bool)containingType.Evaluate(apiIsAbstractTypeExpression) && (bool)containingType.Evaluate(apiIsSealedTypeExpression))
            {
                // the property's containing type is static if it's abstract and sealed
                // members of a static class cannot be used in XAML.
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_nonXamlParent, writer);
            }
            else if (IsExcludedSubClass(containingType))
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_parentIsExcludedSubClass, writer);
            }
            else if (!DoesParentSupportXaml(reflection))
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_nonXamlParent, writer);
            }
            else if (propertyVisibility != "public")
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_notPublic, writer);
            }
            else if (isAbstract)
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_abstract, writer);
            }
            else if (parameters.Count > 0)
            {
                // per DDUERELTools bug 1373: indexer properties cannot be used in XAML
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_nonXaml, writer);
            }
            else if (IsContentProperty(reflection) && !returnTypeIsReadonlyStruct)
            {
                PropertyContentElementUsageSimple(reflection, writer);
            }
            else if (!isSettable || !isSetterPublic)
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_readOnly, writer);
            }
            else if (returnTypeIsAbstract)
            {
                WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_abstractType, returnType, writer);
            }
            else if (IsPrimitiveType(returnTypeId))
            {
                PropertyAttributeUsage(reflection, writer);
            }
            else if (returnTypeSubgroup == "enumeration")
            {
                PropertyAttributeUsage(reflection, writer);
            }
            else
            {
                bool hasDefaultConstructor = HasDefaultConstructor(returnType);
                if (HasTypeConverterAttribute(returnType))
                {
                    if (hasDefaultConstructor && !returnTypeIsReadonlyStruct)
                    {
                        PropertyElementUsageGrande(reflection, writer);
                    }
                    PropertyAttributeUsage(reflection, writer);
                }
                else if (hasDefaultConstructor && !returnTypeIsReadonlyStruct)
                {
                    PropertyElementUsageGrande(reflection, writer);
                }
                else
                {
                    WriteXamlBoilerplate(XamlBoilerplateID.propertyXamlSyntax_nonXaml, writer);
                }
            }
        }

        // A simple Property Element Usage block for a content property
        // syntax looks like: 
        //   <object>
        //     <linkToType .../>
        //   </object>
        private void PropertyContentElementUsageSimple(XPathNavigator propertyReflection, SyntaxWriter writer)
        {
            string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlContentElementUsageHeading);
            XPathNavigator returnType = propertyReflection.SelectSingleNode(apiReturnTypeExpression);

            // start the syntax block
            writer.WriteStartSubBlock(xamlBlockId);

            //   <object>
            writer.WriteString("<");
            writer.WriteParameter("object");
            writer.WriteString(">");
            writer.WriteLine();
            //       <linkToType .../>
            writer.WriteString("  <");
            WriteTypeReference(returnType, writer);
            writer.WriteString(" .../>");
            writer.WriteLine();
            //   </object>
            writer.WriteString("</");
            writer.WriteParameter("object");
            writer.WriteString(">");

            writer.WriteEndSubBlock();
        }

        // A grandiose Property Element Usage block
        // syntax looks like: 
        //   <object>
        //     <object.PropertyName>
        //       <linkToType .../>
        //     </object.PropertyName>
        //   </object>
        private void PropertyElementUsageGrande(XPathNavigator propertyReflection, SyntaxWriter writer)
        {
            string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlPropertyElementUsageHeading);
            string propertyName = (string)propertyReflection.Evaluate(apiNameExpression);
            XPathNavigator returnType = propertyReflection.SelectSingleNode(apiReturnTypeExpression);

            // start the syntax block
            writer.WriteStartSubBlock(xamlBlockId);

            //   <object>
            writer.WriteString("<");
            writer.WriteParameter("object");
            writer.WriteString(">");
            writer.WriteLine();
            //     <object.PropertyName>
            writer.WriteString("  <");
            writer.WriteParameter("object");
            writer.WriteString(".");
            writer.WriteIdentifier(propertyName);
            writer.WriteString(">");
            writer.WriteLine();
            //       <linkToType .../>
            writer.WriteString("    <");
            WriteTypeReference(returnType, writer);
            writer.WriteString(" .../>");
            writer.WriteLine();
            //     </object.PropertyName>
            writer.WriteString("  </");
            writer.WriteParameter("object");
            writer.WriteString(".");
            writer.WriteIdentifier(propertyName);
            writer.WriteString(">");
            writer.WriteLine();
            //   </object>
            writer.WriteString("</");
            writer.WriteParameter("object");
            writer.WriteString(">");

            writer.WriteEndSubBlock();
        }

        // An Attribute Usage block
        private void PropertyAttributeUsage(XPathNavigator propertyReflection, SyntaxWriter writer)
        {
            string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlAttributeUsageHeading);
            string propertyName = (string)propertyReflection.Evaluate(apiNameExpression);
            XPathNavigator returnType = propertyReflection.SelectSingleNode(apiReturnTypeExpression);

            // start the syntax block
            writer.WriteStartSubBlock(xamlBlockId);

            // syntax looks like: 
            //   <object PropertyName="linkToType" .../>
            writer.WriteString("<");
            writer.WriteParameter("object");
            writer.WriteString(" ");
            writer.WriteIdentifier(propertyName);
            writer.WriteString("=\"");
            WriteTypeReference(returnType, writer);
            writer.WriteString("\" .../>");

            writer.WriteEndSubBlock();
        }

        public override void WriteEventSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            string eventName = (string)reflection.Evaluate(apiNameExpression);
            string eventVisibility = (string)reflection.Evaluate(apiVisibilityExpression);
            bool isAbstract = (bool)reflection.Evaluate(apiIsAbstractProcedureExpression);
            XPathNavigator eventHandler = reflection.SelectSingleNode(apiHandlerOfEventExpression);

            XPathNavigator containingType = reflection.SelectSingleNode(apiContainingTypeExpression);
            string containingTypeSubgroup = (string)containingType.Evaluate(apiSubgroupExpression);
            bool containingTypeIsAbstract = (bool)containingType.Evaluate(apiIsAbstractTypeExpression);
            bool containingTypeIsSealed = (bool)containingType.Evaluate(apiIsSealedTypeExpression);

            if (containingTypeSubgroup == "interface")
            {
                WriteXamlBoilerplate(XamlBoilerplateID.eventXamlSyntax_noXamlSyntaxForInterfaceMembers, writer);
            }
            else if (containingTypeIsAbstract && containingTypeIsSealed)
            {
                // the event's containing type is static if it's abstract and sealed
                // members of a static class cannot be used in XAML.
                WriteXamlBoilerplate(XamlBoilerplateID.eventXamlSyntax_nonXamlParent, writer);
            }
            else if (IsExcludedSubClass(containingType))
            {
                WriteXamlBoilerplate(XamlBoilerplateID.eventXamlSyntax_parentIsExcludedSubClass, writer);
            }
            else if (!DoesParentSupportXaml(reflection))
            {
                WriteXamlBoilerplate(XamlBoilerplateID.eventXamlSyntax_nonXamlParent, writer);
            }
            else if (eventVisibility != "public")
            {
                WriteXamlBoilerplate(XamlBoilerplateID.eventXamlSyntax_notPublic, writer);
            }
            else if (isAbstract)
            {
                WriteXamlBoilerplate(XamlBoilerplateID.eventXamlSyntax_abstract, writer);
            }
            else
            {
                // start the syntax block
                string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlAttributeUsageHeading);
                writer.WriteStartSubBlock(xamlBlockId);

                // syntax looks like: 
                //   <object eventName="eventHandlerLink" .../>
                writer.WriteString("<");
                writer.WriteParameter("object");
                writer.WriteString(" ");
                writer.WriteIdentifier(eventName);
                writer.WriteString("=\"");
                WriteTypeReference(eventHandler, writer);
                writer.WriteString("\" .../>");

                writer.WriteEndSubBlock();
            }
        }

        public override void WriteAttachedEventSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            string eventName = (string)reflection.Evaluate(apiNameExpression);
            string containingTypeName = (string)reflection.Evaluate(apiContainingTypeNameExpression);
            XPathNavigator eventHandler = reflection.SelectSingleNode(apiHandlerOfEventExpression);

            // xaml syntax block for attached event
            string xamlBlockId = System.Enum.GetName(typeof(XamlHeadingID), XamlHeadingID.xamlAttributeUsageHeading);
            writer.WriteStartSubBlock(xamlBlockId);

            writer.WriteString("<");
            writer.WriteParameter("object");
            writer.WriteString(" ");
            writer.WriteIdentifier(containingTypeName + "." + eventName);
            writer.WriteString("=\"");
            WriteTypeReference(eventHandler, writer);
            writer.WriteString(string.Format("\" .../>"));

            writer.WriteEndSubBlock();
        }

        public override void WriteFieldSyntax(XPathNavigator reflection, SyntaxWriter writer)
        {
            WriteXamlBoilerplate(XamlBoilerplateID.fieldOverviewXamlSyntax, writer);
        }

        // References

        private void WriteTypeReference(XPathNavigator reference, SyntaxWriter writer)
        {
            switch (reference.LocalName)
            {
                case "arrayOf":
                    int rank = Convert.ToInt32(reference.GetAttribute("rank", String.Empty));
                    XPathNavigator element = reference.SelectSingleNode(typeExpression);
                    WriteTypeReference(element, writer);
                    writer.WriteString("[");
                    for (int i = 1; i < rank; i++) { writer.WriteString(","); }
                    writer.WriteString("]");
                    break;
                case "pointerTo":
                    XPathNavigator pointee = reference.SelectSingleNode(typeExpression);
                    WriteTypeReference(pointee, writer);
                    writer.WriteString("*");
                    break;
                case "referenceTo":
                    XPathNavigator referee = reference.SelectSingleNode(typeExpression);
                    WriteTypeReference(referee, writer);
                    break;
                case "type":
                    string id = reference.GetAttribute("api", String.Empty);

                    XPathNavigator outerTypeReference = reference.SelectSingleNode(typeOuterTypeExpression);
                    if (outerTypeReference != null)
                    {
                        WriteTypeReference(outerTypeReference, writer);
                        writer.WriteString(".");
                    }

                    WriteNormalTypeReference(id, writer);
                    XPathNodeIterator typeModifiers = reference.Select(typeModifiersExpression);
                    while (typeModifiers.MoveNext())
                    {
                        WriteTypeReference(typeModifiers.Current, writer);
                    }
                    break;
                case "template":
                    string name = reference.GetAttribute("name", String.Empty);
                    writer.WriteString(name);
                    XPathNodeIterator modifiers = reference.Select(typeModifiersExpression);
                    while (modifiers.MoveNext())
                    {
                        WriteTypeReference(modifiers.Current, writer);
                    }
                    break;
                case "specialization":
                    writer.WriteString("<");
                    XPathNodeIterator arguments = reference.Select(specializationArgumentsExpression);
                    while (arguments.MoveNext())
                    {
                        if (arguments.CurrentPosition > 1) writer.WriteString(", ");
                        WriteTypeReference(arguments.Current, writer);
                    }
                    writer.WriteString(">");
                    break;
            }
        }

        private void WriteNormalTypeReference(string reference, SyntaxWriter writer)
        {
            switch (reference)
            {
                case "T:System.Void":
                    writer.WriteReferenceLink(reference, "void");
                    break;
                case "T:System.String":
                    writer.WriteReferenceLink(reference, "string");
                    break;
                case "T:System.Boolean":
                    writer.WriteReferenceLink(reference, "bool");
                    break;
                case "T:System.Byte":
                    writer.WriteReferenceLink(reference, "byte");
                    break;
                case "T:System.SByte":
                    writer.WriteReferenceLink(reference, "sbyte");
                    break;
                case "T:System.Char":
                    writer.WriteReferenceLink(reference, "char");
                    break;
                case "T:System.Int16":
                    writer.WriteReferenceLink(reference, "short");
                    break;
                case "T:System.Int32":
                    writer.WriteReferenceLink(reference, "int");
                    break;
                case "T:System.Int64":
                    writer.WriteReferenceLink(reference, "long");
                    break;
                case "T:System.UInt16":
                    writer.WriteReferenceLink(reference, "ushort");
                    break;
                case "T:System.UInt32":
                    writer.WriteReferenceLink(reference, "uint");
                    break;
                case "T:System.UInt64":
                    writer.WriteReferenceLink(reference, "ulong");
                    break;
                case "T:System.Single":
                    writer.WriteReferenceLink(reference, "float");
                    break;
                case "T:System.Double":
                    writer.WriteReferenceLink(reference, "double");
                    break;
                case "T:System.Decimal":
                    writer.WriteReferenceLink(reference, "decimal");
                    break;
                default:
                    writer.WriteReferenceLink(reference);
                    break;
            }
        }

        // utility routines


        // A default constructor is a a parameterless, public constructor method
        // This is called for:
        //  a class
        //  the declaring type of a member
        //  the type of a property
        private bool HasDefaultConstructor(XPathNavigator typeReflection)
        {
            // all structs have implicit default constructors
            string subgroup = (string)typeReflection.Evaluate(apiSubgroupExpression);
            if (subgroup == "structure")
                return true;

            return (bool)typeReflection.Evaluate(hasDefaultConstructorExpression);
        }

        // This is called to check for a "TypeConverterAttribute" on:
        //   a class or structure topic
        //   the declaring type of a property or event member
        //   the type of a property
        private bool HasTypeConverterAttribute(XPathNavigator typeReflection)
        {
            return (bool)typeReflection.Evaluate(hasTypeConverterAttributeExpression);
        }

        // Get the id of the content property, if any, for the property's containing type
        // return true if the content property id matches the current property's id 
        private bool IsContentProperty(XPathNavigator propertyReflection)
        {
            string propertyName = (string)propertyReflection.Evaluate(apiNameExpression);
            XPathNavigator containingType = propertyReflection.SelectSingleNode(apiContainingTypeExpression);
            string containingTypeName = (string)containingType.Evaluate(apiNameExpression);
            string namespaceId = (string)propertyReflection.Evaluate(apiContainingNamespaceIdExpression);
            string propertyId = string.Concat("P:", namespaceId.Substring(2), ".", string.Concat(containingTypeName, ".", propertyName));
            string contentPropertyId = (string)containingType.Evaluate(contentPropertyIdExpression);
            if (propertyId == contentPropertyId)
                return true;
            else
                return false;
        }

        // Check the list of subclasses to exclude
        // This is called to check the class ancestors of
        //   a class
        //   the declaring type of a property or event member
        private bool IsExcludedSubClass(XPathNavigator typeReflection)
        {
            XPathNodeIterator ancestors = (XPathNodeIterator)typeReflection.Evaluate(apiAncestorsExpression);

            foreach (XPathNavigator ancestor in ancestors)
            {
                string ancestorId = ancestor.GetAttribute("api", string.Empty);
                if (excludedAncestorList.Contains(ancestorId))
                    return true;
            }
            return false;
        }

        // Check the parent type of a property or event. 
        // Does it have the necessary characteristics so the property or event can be used in XAML? 
        // Is PARENT CLASS abstract OR does it have a default ctor OR a class-level TypeConverter attribute?
        private bool DoesParentSupportXaml(XPathNavigator memberReflection)
        {
            XPathNavigator containingType = memberReflection.SelectSingleNode(apiContainingTypeExpression);
            if ((bool)containingType.Evaluate(apiIsAbstractTypeExpression))
                return true;

            if (HasDefaultConstructor(containingType))
                return true;

            if (HasTypeConverterAttribute(containingType))
                return true;

            // A property that returns a String doesn't need a TypeConverterAttribute, so return true here
            XPathNavigator returnType = memberReflection.SelectSingleNode(apiReturnTypeExpression);
            if (returnType != null)
            {
                string returnTypeId = returnType.GetAttribute("api", string.Empty);
                if (returnTypeId == "T:System.String")
                    return true;
            }

            return false;
        }

        private bool IsPrimitiveType(string typeId)
        {
            // The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, Char, Double, and Single.
            switch (typeId)
            {
                case "T:System.Boolean":
                case "T:System.Byte":
                case "T:System.SByte":
                case "T:System.Int16":
                case "T:System.UInt16":
                case "T:System.Int32":
                case "T:System.UInt32":
                case "T:System.Int64":
                case "T:System.UInt64":
                case "T:System.IntPtr":
                case "T:System.Char":
                case "T:System.Double":
                case "T:System.Single":
                case "T:System.String": // String is not a primitive but is treated as one for this XAML purpose
                    return true;
                default:
                    return false;
            }
        }


        private XPathExpression hasTypeConverterAttributeExpression = XPathExpression.Compile("boolean(attributes/attribute/type[@api='T:System.ComponentModel.TypeConverterAttribute'])");

        private XPathExpression hasDefaultConstructorExpression = XPathExpression.Compile("boolean(typedata/@defaultConstructor)");

        private XPathExpression contentPropertyNameExpression = XPathExpression.Compile("string(attributes/attribute[type[contains(@api,'.ContentPropertyAttribute')]]/argument/value/.)");
        private XPathExpression contentPropertyIdExpression = XPathExpression.Compile("string(typedata/@contentProperty)");
        private XPathExpression ancestorContentPropertyIdExpression = XPathExpression.Compile("string(family/ancestors/type/@contentProperty)");

        private XPathExpression noSettablePropertiesExpression = XPathExpression.Compile("boolean(typedata/@noSettableProperties)");

        private XPathExpression apiIsSetterPublicExpression = XPathExpression.Compile("boolean((memberdata[@visibility='public'] and not(propertydata[@set-visibility!='public'])) or propertydata[@set-visibility='public'])");
    }

    public enum XamlBoilerplateID
    {
        // boilerplate for classes in xaml assemblies
        classXamlSyntax_abstract,
        classXamlSyntax_excludedSubClass,
        classXamlSyntax_noDefaultCtor,
        classXamlSyntax_noDefaultCtorWithTypeConverter,
        // boilerplate for structs in xaml assemblies
        structXamlSyntax_nonXaml,
        structXamlSyntax_attributeUsage,
        // boilerplate for events in xaml assemblies
        eventXamlSyntax_parentIsExcludedSubClass,
        eventXamlSyntax_noXamlSyntaxForInterfaceMembers,
        eventXamlSyntax_nonXamlParent,
        eventXamlSyntax_notPublic,
        eventXamlSyntax_abstract,
        eventXamlSyntax_nonXaml,
        // boilerplate for properties in xaml assemblies
        propertyXamlSyntax_parentIsExcludedSubClass,
        propertyXamlSyntax_noXamlSyntaxForInterfaceMembers,
        propertyXamlSyntax_nonXamlParent,
        propertyXamlSyntax_notPublic,
        propertyXamlSyntax_abstract,
        propertyXamlSyntax_readOnly,
        propertyXamlSyntax_abstractType,
        propertyXamlSyntax_nonXaml,
        // syntax used with all enums in xaml assemblies
        enumerationOverviewXamlSyntax,
        // boilerplate used with all method, field, etc. in xaml assemblies
        delegateOverviewXamlSyntax,
        interfaceOverviewXamlSyntax,
        constructorOverviewXamlSyntax,
        fieldOverviewXamlSyntax,
        methodOverviewXamlSyntax,
        // boilerplate used with all types and members in all non-xaml assemblies
        nonXamlAssemblyBoilerplate
    }

    // XAML headings
    public enum XamlHeadingID
    {
        xamlAttributeUsageHeading,
        xamlObjectElementUsageHeading,
        xamlPropertyElementUsageHeading,
        xamlContentElementUsageHeading,
        xamlSyntaxBoilerplateHeading
    }


}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.