summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/BuildAssembler/SyntaxComponents/XamlUsageSyntax.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/SyntaxComponents/XamlUsageSyntax.cs')
-rw-r--r--tools/Sandcastle/Source/BuildAssembler/SyntaxComponents/XamlUsageSyntax.cs950
1 files changed, 950 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/SyntaxComponents/XamlUsageSyntax.cs b/tools/Sandcastle/Source/BuildAssembler/SyntaxComponents/XamlUsageSyntax.cs
new file mode 100644
index 0000000..99081c5
--- /dev/null
+++ b/tools/Sandcastle/Source/BuildAssembler/SyntaxComponents/XamlUsageSyntax.cs
@@ -0,0 +1,950 @@
+// Copyright (c) Microsoft Corporation. All 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
+ }
+
+
+}