Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NET Core 3.1 WinForms Designer incompatibility with WPF User Control

Over a year ago I began writing a .NET Framework 4.6.1 app using Windows Forms. At the time I knew about WPF, yet was familiar with Windows Forms and it had most of the controls I needed. For the missing controls, I wrote two in Windows Forms and one in WPF. All of these coexisted fine, with the WPF control containerized within an element host.

This week I began the migration process to .NET Core 3.1. My tests with a copy of the project were positive, as well as initial results with the actual migration. After minor refactoring, the solution built and ran without issue. Then the gremlin appeared after opening the main UI form in the WinForms Designer. Back in .NET Framework, all of my custom controls appeared inside the Designer's Toolbox, providing easy drag-and-drop onto the form. In .NET Core, only my WinForms controls appeared in the Toolbox, not my WPF control. Because the Designer could not see that control, it stripped it from the Form's designer code, leaving an empty element host behind.

Here's the kicker. After reverting the Designer's changes, any direct manual edits to the Form's designer code is accepted, and building the project succeeds and runs fine. So for some reason the Designer does not like WPF controls in WinForms.

Things I've tried:

  • During my testing I discovered that the main WinForms UI needed both "UseWindowsForms" and "UseWPF" set to "true" for the project to compile. I then added the "UseWindowsForms" parameter to the WPF user control library. This caused the control to appear in the Designer's Toolbox, yet attempting to add the control resulted in this error: "Failed to create component ... Microsoft.DotNet.DesignTools.Client.DesignToolsServerException ... Make sure the type implements IComponent and provides an appropriate public constructor. Appropriate constructors either take no parameters or take a single IContainer parameter." And the existing WPF control in the code was still removed.
  • I copied the WPF control from the library to the main UI project, edited the namespace, and removed the library project reference. Same result as above.
  • Created a new Windows Forms User Control library, added "UseWPF" to the project, and copied the WPF control to this library. Same result as above.
  • Back to the test copy of my project, I followed Microsoft's guides for "try-convert" and "upgrade-assistant". The latter seemed promising at first, as it replaced, modified, or removed outdated referenced and packages. But, no success.
  • Tried the above migration steps with both .NET Core 3.1 and .NET 5. Same results.

The point I'm at now is to keep manually editing the Form's designer code. Not ideal for large changes, and also not sustainable if/when this project is passed to another developer. Any thoughts? Should I attempt porting the Windows Forms UI to WPF? Or is this simply a maturity issue with the still relatively new .NET Core Windows Forms Designer?

Visual Studio version: Community 2019 16.9.3

Screenshot of IComponent error: enter image description here

like image 812
Brett Avatar asked Nov 06 '25 02:11

Brett


1 Answers

I finally figured out a workaround; the idea was sparked by the Microsoft Docs page for the ElementHost control: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.integration.elementhost?view=netcore-3.1

In essence, move the WPF control hosting from the main UI into a WinForms control library. Hence, the User control in this WinForms control library will be a wrapper for the WPF control. Here are the steps I took in my test VS solution:

  1. Remove the "true" entry from the main UI project file I had added during testing.
  2. In the new WinForms control library, add "true" to this project file underneath the "true" entry. This enables the library to be a bridge between the two UI frameworks.
  3. If the WPF control to host is in a dedicated control library (like mine), then add this project as a dependency in the WinForms control library.
  4. Create a new User control in the WinForms library, if there isn't one already.
  5. In the Designer, add a panel container to the control with "Fill" docking. I named my panel as "panelWpf".
  6. Here is where the Microsoft Doc comes in. In the code behind file for the WinForms control, I first added an ElementHost control and the WPF control as private global variables. Then, in the WinForms "Load" event, I set the ElementHost docking style, added the WPF as a child, and finally added ElementHost as a control to the "panelWpf" container. Below is the code from this file. "WpfControlLibrary31" is my WPF control library project, and "TestControl31" is the WPF control itself. Lastly, "WpfTest" is the name of the wrapper WinForms User control.
  7. After building the WinForms control library, it appeared in the main UI project's Toolbox, and I was able to add it to the form like any other Windows Forms control. The next steps will be to add event handlers, getters, setters, etc. to the control for the needed interaction.
using System;
using System.Windows.Forms;
using System.Windows.Forms.Integration;


namespace WinFormsLibrary
{
    public partial class WpfTest : UserControl
    {
        // ElementHost for the WPF control
        private ElementHost host = new ElementHost();
        // WPF control to be hosted
        private WpfControlLibrary31.TestControl31 uc = new WpfControlLibrary31.TestControl31();

        public WpfTest()
        {
            InitializeComponent();
        }

        private void WpfTest_Load(object sender, EventArgs e)
        {
            // set the docking style for the ElementHost
            host.Dock = DockStyle.Fill;

            // add the WPF control as a child of ElementHost
            host.Child = uc;

            // add the ElementHost as a control of the panel container
            panelWpf.Controls.Add(host);
        }
    }
}

Thoughts:

  1. Some may wonder why I used the panel container. And in this simple experiment it was overkill; I could have simply docked the ElementHost to the control itself. However, if the WinForms User control has a more complex design, then the panel will be a placeholder while still allowing use of the Designer. Also, if a border or similar design is needed around the WPF control, then this should be possible with the panel.
  2. Having the ElementHost and WPF control object as global allows access from all the control's methods, obviously, just like any controls added in the Designer itself.
  3. The WPF control to host does not need to be in a dedicated WPF control library project. If it is a pre-existing WPF control (e.g. MediaElement), then use it for the global WPF object.
  4. This WinForms control library is what I have been needing to consolidate and improve efficiency of my custom controls. So this issue with the .NET Core WinForms Designer turned out to be a blessing in disguise.

What are your thoughts? Thanks for the brainstorming help!

like image 58
Brett Avatar answered Nov 08 '25 19:11

Brett



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!