Blog

From windows to tiles: Leveraging reflection to inspect and contrast WPF with WinRT XAML

To begin with, our primal, simple aim was contrasting several concepts as applied in good old WPF with the way they have been implemented in WinRT . To actually enable a both exhaustive and reasonable comparison between both UI frameworks, we pragmatically decided to unleash some reflection functionality on the respectively affected assemblies. That being said, it turned out that scouring all eligible assemblies for usages of a certain type, let´s say ICommand, appears not to be as straight forward in a Windows Store app as it does in WPF. For instance, let´s assume we want to determine all occurrences of implementations of the ICommand interface within WPF; therefore, we require some functionality to examine all types being defined in WPF-related assemblies such as WindowsBase, PresentationCore and PresentationFramework. Taking a WPF project as granted, we may now exploit the .NET-Framework’s capability to access the current application domain and simply iterate over all assemblies therein:

private IEnumerable<Type> SearchCurrentAppDomainForSubtypesOf(Type superType)
        {
            return AppDomain
                .CurrentDomain
                .GetAssemblies()
                .SelectMany(assembly => assembly.GetTypes())
                .Where(type => superType.IsAssignableFrom(type));
        } 

 

Unfortunately, this approach proved to be desperately unsatisfactory in our Windows Store app as we could not access our application´s domain from within the WinRT API. Thus, we required a different strategy.

Examining our Windows store app project´s structure in a bit more detail, we figured out that the VS-generated references linked to the “Windows SDK” that comes shipped as “Windows.winmd” and to a set of DLLs called “.NET for Windows Store apps”.

Conveniently, the Windows.winmd is supplemented with an XML-formatted file (named “Windows.xml”) containing metadata of its types, properties and namespaces. Eventually, we decided to utilize this file by simply traversing its tree and successively reflecting any type contained.

 

private async Task<List<Type>> SearchWindowsWinmdForSubtypesOf(Type superType, 
        StorageFile windowsXmlFile)
        {
            var result = new List<Type>();
 
            var document = await XmlDocument.LoadFromFileAsync(windowsXmlFile);
            var xml = document.GetXml();
            var xdoc = XDocument.Parse(xml);
 
            foreach (var member in xdoc.Descendants("member"))
            {
                var memberName = member.Attribute("name").Value;
 
                if (memberName.ToUpper().StartsWith("T:"))
                {
                    var typeString = memberName.Substring(2);
                    var type = Type.GetType(typeString + 
                        ", Version=255.255.255.255" +
                        ", Culture=neutral" +
                        ", PublicKeyToken=null" +
                        ", ContentType=WindowsRuntime");
 
                    if (superType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
                    {
                        result.Add(type);
                    }
                }
            }
            return result;
        }

 

Similarly, we subsequently implemented a function to search the remaining DLLs that are collectively referred to as “.NET for Windows Store apps”. Even though these assemblies are available as plain old DLLs, we could not simply reflect them by parsing their file path as the Assembly.LoadFrom(assemblyFile:String) method does not exist anymore. Instead, we need an assembly´s full name to load it. Fortunately, we could find a further XML-file (“FrameworkList.xml”) in one of the referenced directory´s subfolders containing a list of all comprised assemblies including their full names. Finally, we used this file to iterate over all assemblies to extract their full names and to reflect them subsequently.

 

private async Task<List<String>> SearchDotNetForWindowsStoreAppsForSubtypesOf(
        Type superType, StorageFile frameworkListXmlFile)
        {
            var result = new List<String>();
 
            var document = await XmlDocument.LoadFromFileAsync(frameworkListXmlFile);
            var xml = document.GetXml();
            var xdoc = XDocument.Parse(xml);
 
            foreach (var fileList in xdoc.Descendants("FileList"))
            {
                foreach (var file in xdoc.Descendants("File"))
                {
                    var name = file.Attribute("AssemblyName").Value;
                    var version = file.Attribute("Version").Value;
                    var culture = file.Attribute("Culture").Value;
                    var publicKeyToken = file.Attribute("PublicKeyToken").Value;
 
                    var fullName = name + 
                        ", Version=" + version + 
                        ", Culture=" + culture + 
                        ", PublicKeyToken=" + publicKeyToken;
                    var assemblyName = new AssemblyName(fullName);
 
                    try
                    {
                        var assembly = Assembly.Load(assemblyName);
                        var types = assembly.DefinedTypes;
 
                        foreach (var type in types)
                        {
                            if (superType.GetTypeInfo().IsAssignableFrom(type))
                            {
                                result.Add(type.Namespace + "." + type.Name);
                            }
                        }
                    }
                    catch (Exception) { result.Add("Skipped " + fullName); }
                }
            }
            return result;
        }

 

Want to know more about our services, products or our UX process?
We are looking forward to hearing from you.

Senior UX Manager
+49 681 959 3110

Before sending your request, please confirm that we may contact you by clicking in the checkbox above.