14

I have a WPF user control like this...

namespace WpfApplication1
{
    public partial class MyControl : UserControl
    {
    ......
    }
}

I also have a win form to contain this WPF user control...

namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{

    public Form1()
    {

        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        ElementHost ctrlHost = new ElementHost();
        ctrlHost.Dock = DockStyle.Fill;
        WpfApplication1.MyControl win = new WpfApplication1.MyControl();
        ctrlHost.Child = win;
        this.Controls.Add(ctrlHost);
    }
}
}

I have one more parent win form that has a button. Clicking the button will open the Form1 that contains the ElementHost.

namespace WindowsFormsApplication4
{
    public partial class Parent : Form
    {
        public Parent()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form1 form1 = new Form1();
            form1.Show();

        }
    }
}

My application runs the Parent form by default...

Application.Run(new Parent());

The problem I'm facing is strange. When i run the application, the parent form opens and on clicking the button the child window form containing the WPF control also opens. But the problem is the size of parent form window automatically shrinks(the window displaces, restores itself and the controls and font becomes smaller in it.) as soon as the WPF control form pops up. If I comment the content of the 'Form1_Load' function then the parent window does not shrink. To check the worst case i commented everything in 'Form1_Load' except

ElementHost ctrlHost = new ElementHost();

line. The mere presence of this line itself makes the parent form shrink as I mentioned earlier. I tried to search in internet for this problem extensively. I was not able to find a solution. Please help me with a answer. I'm exhausted....

balaji
  • 216
  • 2
  • 7
  • http://www.codeproject.com/Tips/130414/Host-Windows-Form-Controls-in-WPF please look into this link, i think please provide your window form specific width and height and then tried to load your child user control. As due to child adding content is added to your form and it come to know that it requires more space, thats why its shrinking. – Ashok Rathod Oct 17 '14 at 02:57
  • thanks for your comments Ashok. I tried setting width and height for the parent window. But still the same problem exists... – balaji Oct 17 '14 at 07:10
  • Any progress on this? I have the exact same problem. – user958578 Feb 12 '15 at 11:02
  • I’ve encountered the same thing. A windows form with an empty ElementHost causes the parent window to shrink. – iCode Jul 22 '22 at 01:54

1 Answers1

15

I commented above that I had the same issue and have since resolved it. I'm writing up my changes here for anyone else.

As observed above, the behaviour seems to occur whenever using Windows UI scaling in an WinForms application and the Just In Time (JIT) Compiler processes anything from the WPF libraries. In my case, entering a method that contains code that opens the WPF version of MessageBox will make it happen. Ordinarily Windows will handle basic scaling for you, rendering to a bitmap offscreen and then drawing it on screen but scaled up. When WPF loads it seems to take over, as if it's saying to Windows, "Hey.. i got this..". After that Windows stops scaling the WinForms for you and you end up with the 1x scale version and often some confused controls. The WPF portion however is handling its own scaling and looks fine.

So the way I went about solving it was to tell Windows that I would handle the WinForms scaling. To enable that you have to add this to your application manifest (dll manifest is ignored)

<asmv3:application>
  <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
    <dpiAware>true</dpiAware>
  </asmv3:windowsSettings>
</asmv3:application>

OR uncomment the following section if it is already in there:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
  </windowsSettings>
</application>

You can add a manifest file:

Right click on application project -> Add -> New item... -> Application Manifest File

Then in...

Application Project -> Properties -> Application -> Resources

Make sure "Manifest" is set to app.manifest

You can now find that file and add the XML above into the root <asmv1:assembly>element.

If you've taken the default application manifest and added that element it probably looks something like this

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"  xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <applicationRequestMinimum>
        <defaultAssemblyRequest permissionSetReference="Custom" />
        <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
      </applicationRequestMinimum>
    </security>
  </trustInfo>
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</asmv1:assembly>

Now when you start your WinForms app you will notice it's much crisper because it's being rendered at high dpi instead of 96dpi and then scaled up to fill the space.

You'll probably notice that a lot of your images have shrunk!! In my case Buttons, MenuStripItems and ToolStripItems did not scale as desired.

What I found was that most controls have a method that you can override as below

protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
    base.ScaleControl(factor, specified);
}

This is called when the application launches and filters through your controls from the main form. My Windows is set to 200%, my main form's scaling mode was set to DPI and all the forms were designed at 100% scale (96dpi). I changed everything in my first attempts to fix the problem to inherit the scaling mode and this was what worked for me, if you're using font or none i suspect it will work just the same but I haven't tried it.

As mine was 200% UI scaling when this method was called factor was simply {2.0, 2.0} which I then used to recreate a scaled Image in Buttons, and to increase the ImageScalingSize on each of the Items of MenuStrip and ToolStrip since these do not receive the ScaleControl call. If you never added the XML above then this method is still called but will only ever have {1.0, 1.0} for factor, which isn't helpful. Note: if you're using image list then don't dynamically set the image if in DesignMode or the ImageList will become unset and when you save then nothing will be set

Also not that factor is a factor from the current. What you will notice is if you move the application between different dpi monitors you will get 2.0, then 0.5, then 2.0, then 0.5, etc.

Now my WinForms application looks super crisp and it can call WPF ui elements without going crazy! yyayyyyy

Hope this helps someone

Jerther
  • 5,558
  • 8
  • 40
  • 59
dten
  • 2,364
  • 21
  • 28