question

MERUNKUMARMAITY-4120 avatar image
0 Votes"
MERUNKUMARMAITY-4120 asked MERUNKUMARMAITY-4120 commented

How to DPI aware WPF applicaton

n daily life we have to deal with a lot of different types of display size it may be mobile or may be a 4k monitor. The screen resolution vary from display to display. Here another important factor is DPI (Display per inch) which is mainly a scaling factor in windows but have a great relation with screen resolution.

Now I give you an example first suppose I run the visual studio application on a Full HD monitor and the resolution is 1920x1080. Suppose I change my display resolution from full HD (1920x1080) to 1366x768. And after that I run the visual studio again on the same display and I see that the user interface (UI) is get slightly bigger and all the controls,text,icons and buttons are perfectly align according to the current monitor DPI scaling and resolution.

And the UI should get bigger as it happens when we run visual studio and other windows application on lower resolution.

I want to apply that similar effect in my WPF application so that each time the screen resolution and DPI changes, my application will automatically adjust according to the display DPI and resolution. I already try Microsoft per monitor DPI aware for windows 10 and edit the app.Mainfest file and uncomment some code according to the GitHub instructions but nothing works in my case.

I also bind with the screen resolution with my application height and width but it's cover whole the screen I don't want that.

But one thing I understand is I have to get the system DPI and then apply it on my window load event but I don't know how to do that in code.

Here is the MainWindow.xaml code (I put just a little amount of code because it's office project )

 <Window
     x:Class="WpfApp1.MainWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:local="clr-namespace:WpfApp1"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     Name="myMainWindow"
     Title="MainWindow"
     Width="1024"
     Height="547.4"
     AllowsTransparency="True"
     WindowStartupLocation="CenterScreen"
     WindowStyle="None"
     MouseLeftButtonDown="myMainWindow_MouseLeftButtonDown"
     mc:Ignorable="d">
     <Grid Name="MainGrid" Background="#282828">
         <Button
             x:Name="BtnSettings"
             Width="71"
             Height="24"
             Margin="165,14,0,0"
             HorizontalAlignment="Left"
             VerticalAlignment="Top"
             RenderOptions.BitmapScalingMode="NearestNeighbor"
             RenderOptions.ClearTypeHint="Enabled"
             SnapsToDevicePixels="True"
             UseLayoutRounding="True">
             <Button.Content>
                 <TextBlock
                     Margin="0,-2,0,0"
                     FontFamily="Segoe UI"
                     FontSize="10"
                     TextOptions.TextFormattingMode="Display"
                     UseLayoutRounding="True">
                     Settings
                 </TextBlock>
             </Button.Content>
         </Button>
         <Button
             x:Name="BtnAccounts"
             Width="71"
             Height="24"
             Margin="237,14,0,0"
             HorizontalAlignment="Left"
             VerticalAlignment="Top"
             RenderOptions.BitmapScalingMode="NearestNeighbor"
             RenderOptions.ClearTypeHint="Enabled"
             SnapsToDevicePixels="True"
             UseLayoutRounding="True">
             <Button.Content>
                 <TextBlock
                     Margin="0,-2,0,0"
                     FontFamily="Segoe UI"
                     FontSize="10"
                     TextOptions.TextFormattingMode="Display"
                     UseLayoutRounding="True">
                     Accounts
                 </TextBlock>
             </Button.Content>
         </Button>
     </Grid>
 </Window>

And Here is my back-end c# logic code known as MainWindow.xaml.cs

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
    
 namespace WpfApp1
 {
     /// <summary>
     /// Interaction logic for MainWindow.xaml
     /// </summary>
     public partial class MainWindow : Window
     {
         public MainWindow()
         {
             InitializeComponent();
         }
    
         private void myMainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         {
             DragMove();
         }
     }
 }


Another important factor is I also use view box but that does not working as much I wanted. Some people told me that I should use fluid layout and I should use Grid.RowDefinitions and Grid.ColumnDefinitions and I also use * and Auto for resizing and don't use absolute positioning and instead of I should use Margin and padding. I know that it's a issue but my main problem is regarding the DPI and resolution which has nothing to do with absolute positioning.

I should use scale transformation on my MainGrid and that should be bind with the DPI decorator and resolution but I don't have enough ideas that how to do that.

As I say previously that view box is not working because I use the Seoge UI font in my application and if you carefully see my MainWindow.xaml code then you see that I give font size=10 because the latter are taking a very good shape in this size and I also use TextOptions.TextFormattingMode="Display" for my UI design purpose.

My question is how my WPF application automatically detect the screen DPI and resolution and perfectly scale transform according to itself so there no blurry font issue or the Main window is very small etc. Perfectly fit and scale and good looking according to the display.

dotnet-csharpwindows-wpf
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


Did you already consider the “Per Monitor Aware WPF Sample” [https://docs.microsoft.com/en-us/windows/win32/hidpi/declaring-managed-apps-dpi-aware#per-monitor-aware-wpf-sample-walkthrough]?

Also check: https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI.

Are you developing a WPF application bases on “.NET Core”?

0 Votes 0 ·

1 Answer

DaisyTian-1203 avatar image
0 Votes"
DaisyTian-1203 answered MERUNKUMARMAITY-4120 commented

But one thing I understand is I have to get the system DPI and then apply it on my window load event but I don't know how to do that in code.

With .NET 4.6.2 Preview and higher, you can call VisualTreeHelper.GetDpi(Visual visual). It gets the DPI information at which this Visual is measured and rendered. You can also use below code to get the DPI information.

 PresentationSource source = PresentationSource.FromVisual(this);
    
 double dpiX, dpiY;
 if (source != null) {
     dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
     dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
 }

Microsoft WPF team provided a Per Monitor DPI sample on the Github which provides developer info on how to test your WPF application with our Per Monitor DPI feature. You can refer to it to get how to use dpi info in the Window_Loaded.


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I develop my WPF application in .NET 4.7. I try to retrieve the dpi information from VisualTreeHelper.GetDpi(Visual visual) but I get the error visual tree helper does not contain a definition for GetDpi. Though the code you given is working I paste the code in Windows_Load event. But after that how I scale my WPF main window according to this retrieve DPI data?

On another hand the Per monitor DPI is not working in my case as I say previously. If you have already demo project which Is DPI aware then you can give me the download links.

0 Votes 0 ·

@MERUNKUMARMAITY-4120
Could you check if below code work for you ?

     ScaleTransform dpiTransform = new ScaleTransform(dpixRatio, dpiyRatio);
             if (dpiTransform.CanFreeze)
                 dpiTransform.Freeze();
             this.LayoutTransform = dpiTransform;
1 Vote 1 ·

Should I paste this in window load event?

0 Votes 0 ·
Show more comments