Windows Forms Graphic Issue on Windows 10 Os

Windows Forms Graphic Issue on Windows 10 OS

To solve the problem, you can make your application DPI-Aware using either of these options:

  • Application Manifest
  • API calls to SetProcessDPIAware, SetProcessDpiAwareness or SetProcessDpiAwarenessContext

Important Note: It is recommended that you set the process-default DPI
awareness via application manifest, not an API call.

Using Application Manifest File

To make the application DPI-Aware, you can add an Application Manifest File to your project. Then in the app.manifest file, uncomment the part that is related to DPI-Awareness:

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

Then in your app.config file, add EnableWindowsFormsHighDpiAutoResizing setting its value to true:

<appSettings>
<add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />
</appSettings>

For more information take a look at the following topic in Microsoft docs:

  • High DPI Desktop Application Development on Windows

SetProcessDPIAware API call Example

You can use SetProcessDPIAware() method before showing your main form to set your application dpi aware and prevent windows from scaling the application. Also you should check the windows version to be greater than or equals to vista:

static class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetProcessDPIAware();

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
if (Environment.OSVersion.Version.Major >= 6)
SetProcessDPIAware();

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(new Form1());
}
}

Notes

  1. As it's already mentioned above, it is recommended that you set the process-default DPI awareness via application manifest, not an API call.

  2. Before using API calls, read the documentations to know about supported OS and also possible race condition if a DLL caches dpi settings during initialization. Also keep in mind, DLLs should accept the dpi setting of the host process rather than API call themselves.

  3. You may find this DpiHelper class implemented in WinForms for .NET Core 3.0 useful.

Redraw issue on Windows10 with DoubleBuffering and FormBorderStyle.None

For me it looks like an error in OS, but I have found how to make it work without give up on DoubleBuffering and FormBorderStyle=None.

If window style will be extended by

cp.ExStyle |= 0x00080000;   // Turn on WS_EX_LAYERED

then all works as expected.

Why does Visual Studio automatically changes the layout of my form?

Reasoning

This was due to AutoScaleMode property which scales the size and position of objects in winforms based on the difference in Dots per inch (DPI) between different development machines. This is a feature that cannot and should not be changed. For official documentation, see Automatic Scaling in Windows Forms on MSDN.

Let's say there are two machines, machine A and B. Machine A has 96 DPI and scaling factor 100%. Machine B has 144 DPI and 150% scaling factor as its recommended settings. A WinForm was created in machine A and machine B is trying to edit that WinForm.

When Visual Studio in machine B encounters that machine B's DPI is different than the one used to create the WinForm, it automatically scales the objects in the WinForm to try to make the WinForm appear in machine B as how it would look in machine A​​. Hence, this causes some properties in WinForm.Designer.cs file to be automatically changed.

Workaround

In order to continue editing WinForms in high DPI machines without any automatic alignments, we need to set the DPI in high DPI machines to match the DPI in the machines used to create the WinForm. This can be done by adjusting the scaling factor to 100% (96 DPI; right-click on desktop > Display settings) and restarting Visual Studio (or re-login to Windows, if that does not work).

NOTE: The key here is to adjust the DPI to the original DPI of the machines used to create the WinForm. Just adjusting the scaling factor might not work. You might need to play around with the screen resolution.

How to configure an app to run correctly on a machine with a high DPI setting (e.g. 150%)?

Once you go past 100% (or 125% with the "XP-style DPI scaling" checkbox ticked), Windows by default takes over the scaling of your UI. It does so by having your app render its output to a bitmap and drawing that bitmap to the screen. The rescaling of that bitmap makes the text inevitably look fuzzy. A feature called "DPI virtualization", it keeps old programs usable on high resolution monitors.

You have to explicitly let it know that you can handle higher DPI settings by adding the <dpiAware> element to your manifest. The MSDN page is here but it isn't complete since it is omitting the UAC settings. Project + Add New Item, pick "Application Manifest File". Edit the manifest text or copy/paste this:

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

You can also pinvoke SetProcessDPIAware() in your Main() method, necessary for example if you deploy with ClickOnce:

    [STAThread]
static void Main() {
if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // Edit as needed
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();

UPDATE, this common need is finally a bit easier if you use VS2015 Update 1 or higher. The added manifest already has the relevant directive, just remove the comments.


Keyword for search so I can find this post back: dpiAware

.Net DateTimePicker Looks Odd

Apparently this is an issue with .NET Framework 4.5 running on Windows 7 x64 SP1. When I change the target framework to .NET Framework 4.5.1, this issue is resolved. I can't explain why this is happening, but at least there is a work-around for it.

-- EDIT --

I just discovered that the change to framework version 4.5.1 isn't what resolved the issue. When I made that change, Visual Studio automatically added the following to each property group in the csproj:

<Prefer32Bit>false</Prefer32Bit>

After adding this line to each configuration, this issue was resolved. I'm still looking for an explanation as to WHY this fixes the issue, so I can understand how to avoid it in the future.



Related Topics



Leave a reply



Submit