question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

WinUI 3 Cant instantiate a UserControl from a location outside the application package or directory (XamlParseException)

See original GitHub issue

Describe the bug

When instantiating a UserControl from outside the application package an XamlParseException is thrown from the UserControl constructor at this.InitializeComponent().

Exception thrown at 0x773B35D2 (KernelBase.dll) in HostApp.exe: WinRT originate error - 0x80004005 : 'Cannot locate resource from 'ms-appx:///Plugin/PluginUserControl.xaml'.'.
Exception thrown: 'Microsoft.UI.Xaml.Markup.XamlParseException' in WinRT.Runtime.dll
WinRT information: Cannot locate resource from 'ms-appx:///Plugin/PluginUserControl.xaml'.
XAML parsing failed.

Steps to reproduce the bug

See minimal reproducing repository https://github.com/williamfigtree/WinUIPluginIssue. Key steps to recreate:

  1. Create a class library “Plugin” using template “Class Library (WinUI 3 in Desktop)”

  2. Add a UserControl “PluginUserControl” using template “User Control (WinUI 3)” to Plugin.csproj

  3. Create an application “HostApp” using template “Black App, Packaged (WinUI 3 in Desktop)”

  4. Add the “PluginLoadContext” class from this tutorial https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support to HostApp.csproj

    using System;
    using System.Reflection;
    using System.Runtime.Loader;
    
    namespace HostApp
    {
        class PluginLoadContext : AssemblyLoadContext
        {
            private AssemblyDependencyResolver _resolver;
    
            public PluginLoadContext(string pluginPath)
            {
                _resolver = new AssemblyDependencyResolver(pluginPath);
            }
    
            protected override Assembly Load(AssemblyName assemblyName)
            {
                string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
                if (assemblyPath != null)
                {
                    return LoadFromAssemblyPath(assemblyPath);
                }
    
                return null;
            }
    
            protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
            {
                string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
                if (libraryPath != null)
                {
                    return LoadUnmanagedDllFromPath(libraryPath);
                }
    
                return IntPtr.Zero;
            }
        }
    }
    
    
  5. Add the following code to the App constructor. You may need to modify the path to Plugin.dll.

        public App()
        {
            this.InitializeComponent();
    
            // Attempt to load a UserControl from a plugin dll
            // PluginUserControl throws an XamlParsingExcpetion during instantiation
    
            // Locate plugin dll in the Plugin project bin directory
            var rootPath = Path.GetFullPath(@"..\..\..\..\..\..\..\..\", typeof(Program).Assembly.Location);
            var pluginDllPath = Path.Combine(rootPath, @"Plugin\bin\x86\Debug\net5.0-windows10.0.19041.0\Plugin.dll");
    
            // Instantiate PluginUserControl
            var pluginLoadContext = new PluginLoadContext(pluginDllPath);
            using (pluginLoadContext.EnterContextualReflection())
            {
                var pluginUserControl = Activator.CreateInstance("Plugin", "Plugin.PluginUserControl");
            }
        }
    
  6. Build Plugin.csproj

  7. Deploy and debug HostApp.csproj

Expected behavior

The UserControl is instantiated and the UserControl XAML resources supplied by the external project, package, or directory are located.

Screenshots

No response

NuGet package version

No response

Windows app type

  • UWP
  • Win32

Device form factor

Desktop

Windows version

November 2019 Update (18363)

Additional context

This is a blocking issue for applications which require plugins which supply their own UI.

Observed the issue with WinUI 3 1.0.0-preview3.

https://github.com/microsoft/microsoft-ui-xaml/issues/3888 describes a similar requirement but does not come to an appropriate solution as it requires files from the plugin to be copied into the main package. This prevents separate build and distribution of applications and plugins.

https://github.com/microsoft/microsoft-ui-xaml/issues/1365#issuecomment-534803147 and https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support suggest that AssemblyLoadContext is the intended mechanism for plugin support and do not indicate any separate system for XAML resources.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:9
  • Comments:47 (4 by maintainers)

github_iconTop GitHub Comments

7reactions
harvinderscommented, Feb 27, 2022

I have tried https://github.com/microsoft/microsoft-ui-xaml/issues/6299#issuecomment-1023856405 by @williamfigtree and it works for a single UserControl. However, if that UserControl contains another UserControl, then it fails.

So if you have a MainApp that tries to load a UserControlA from a AssemblyX, you would be able to load UserControlA as mentioned. However if there is another UserControlB in AssemblyX and UserControlA uses it in the XAML file, then we get XAML Parsing exception when loading the UserControlA. @RealTommyKlein do you have any suggestion or work around that you can think off.

Also, @marb2000 has mentioned that the WinUI team is concentrating on the core infrastructure this year, instead of adding more controls. Would you consider this issue/feature among core infrastructure tickets that needs to be addressed in 1.1 or 1.2? This issue is preventing us from developing a class of application (plugins with UIs). I am sure many others in the community too would like to see it addressed soon. @marb2000, @MikeHillberg, A guidance would help us immensely to determine the direction for our project.

5reactions
axodoxcommented, Jan 5, 2023

We seem to have found a workaround which allows this to work, it requires two basic things:

  • First you need to use a custom InitializeComponent() implementation, so you specify your package name in the path as described above
  • In addition you need implement a IXamlMetadataProvider interface, and inside it you need to redirect the calls to your custom DLL’s XamlMetadataProvider classes, which you can instantiate with reflection or winrt::create_instance, as they are autogenerated classes their name is known. This implementation is autodetected by tooling and invoked when namespaces and types are resolved in XAML.

Using the above two you will be able to load custom controls including xaml files which reference other custom controls, converters etc. This allows you to create lately discovered plug-ins, without related sets. So you can have a main app deployed, and you can make an optional package later which has UI and load it successfully in the app.

So basically this is already possible however it needs documentation, and the InitializeComponent code generation should be fixed so there is no need for a workaround.

Note we are using UWP + WinUI 2 with C++/WinRT, but maybe somebody can test this on WinUI 3 as well.

Read more comments on GitHub >

github_iconTop Results From Across the Web

XamlParseException when using UserControl from class ...
When I create a fresh Universal Windows App and create the same UserControl inside an app and open the popup, it opens. But...
Read more >
XamlParseException - Could not load file or assembly
I have a WPF Application, WpfApplication1, and I'm referencing a WPF User Control library, WpfControlLibrary1. In the WpfControlLibrary1 ...
Read more >
ResourceDictionary and XAML resource references
Explains how to define a ResourceDictionary element and keyed resources, and how XAML resources relate to other resources that you define as ...
Read more >
WPF UserControl Reuse With MVVM
A UserControl is simply an easy way to create a Control using composition. UserControls are still Controls, and therefore should solely be ...
Read more >
sitemap.xml
... 2012-09-12T15:22:45+00:00 weekly 0.8 https://www.scichart.com/questions/question/create-chart-with-categorical-data-in-x-axis 2022-08-07T17:14:04+00:00 ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found