XamlScenario: Determining if a XAML document is a “WPF” XAML document
An email inside Microsoft asked yesterday for the best way to determine if a XAML document is a “WPF” XAML document. This is my best answer:
.NET 4 Technique:
[requires .NET Framework 4’s System.Xaml.dll that we announced/demoed at PDC08]
This technique avoids creation of any objects specified in the XAML document and can tolerate x:Class or events in the XAML.
- bool isItWpf = IsWpfDocument("window1.xaml");
private static bool IsWpfDocument(string fileName)
{
Type rootType = GetXamlDocumentRootType(fileName);
bool isWpfSubclass = IsSubclassOfWpfType(rootType); //see this method in bottom section of post
return isWpfSubclass;
}
private static Type GetXamlDocumentRootType(string fileName)
{
XmlReader xmlReader = XmlReader.Create(fileName);
XamlXmlReader reader = new XamlXmlReader(xmlReader);
//Advance reader to the first (root) StartObject node (skips all namespace nodes)
while (reader.NodeType != XamlNodeType.StartObject)
{
reader.Read();
}
//Now grab its XamlType, and then the CLR Type.
XamlType rootXamlType = reader.Type;
Type rootType = rootXamlType.UnderlyingType;
return rootType;
}
.NET 3 Techniques:
Option A: Load the entire document via XamlReader.Load and then get the Type of the root object.
This technique does not avoid creation of any objects specified in the XAML document and cannot tolerate x:Class or events in the XAML.
- bool isItWpf = IsWpfDocumentRetro("window1.xaml");
private static bool IsWpfDocumentRetro(string fileName)
{
Type rootType = GetXamlDocumentRootRetro(fileName);
bool isWpfSubclass = IsSubclassOfWpfType(rootType); //see this method in bottom section of post
return isWpfSubclass;
}
private static Type GetXamlDocumentRootRetro(string fileName)
{
XmlReader xmlReader = XmlReader.Create(fileName);
//downside is that the entire document was processed (and the object graph was created.)
Type rootType = XamlReader.Load(xmlReader).GetType();
return rootType;
}
Option B: Use XmlReader and figure out the xmlns mapping to CLR namespace yourself.
This technique avoids creation of any objects specified in the XAML document and can tolerate x:Class or events in the XAML, but is kind of pain to write.
- Use XmlReader to find root element and namespace. Determine CLR Namespace based on parsing “clr-namespace:” uri, or walk all loaded assemblies for [assembly:XmlnsDefinition(…)] attributes to determine mapping from pretty xmlns to CLR-namespace. (we’ll keep this sample as an exercise for the reader).
Function used in both .NET 3 and .NET 4 Solutions
//This function will walk a types class hierarchy and return true if any of the types are from any
//of WPF's main 3 assemblies.
private static bool IsSubclassOfWpfType(Type type)
{
Assembly presentationFramework = typeof(FrameworkElement).Assembly;
Assembly presentationCore = typeof(UIElement).Assembly;
Assembly windowsBase = typeof(DependencyObject).Assembly;
Type baseType = type;
while (baseType != null)
{
Assembly assembly = baseType.Assembly;
if (assembly == presentationFramework
|| assembly == presentationCore
|| assembly == windowsBase)
{
return true;
}
baseType = baseType.BaseType;
}
return false;
}