How to Scale Viewbox height and width according to screen DPI in WPF?

MERUN KUMAR MAITY 576 Reputation points
2021-06-15T18:28:26.257+00:00

Due to design purpose I use fluid Layout in my WPF application. I also use the DPI decorator to adjust my WPF application UI into various screen DPI and resolution.

Here is the DPI Decorator code -

public class DpiDecorator : Decorator
     {
         public DpiDecorator()
         {
             this.Loaded += (s, e) =>
             {
                 System.Windows.Media.Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
                 ScaleTransform dpiTransform = new ScaleTransform(1 / m.M11, 1 / m.M22);
                 if (dpiTransform.CanFreeze)
                     dpiTransform.Freeze();
                 this.LayoutTransform = dpiTransform;
             };
         }
     }

And use it like:

<local:DpiDecorator>
         <Grid Name="MainGrid" Background="#282828">
            <!--Your Controls-->
         </Grid>
     </local:DpiDecorator>

By this DPI Decorator my application works perfectly in every monitor, from 4K to 1366*768. But the only problem is related to the Text rendering. After applying this DPI Decorator class my text became blurry. And to overcome this situation I use the popular Viewbox control. As we know that, the Viewbox is mainly use to scale the child elements. And it's give infinite space to the children elements so that they perfectly stretch and scale according to screen size.

I developing this WPF application in my Lenovo laptop which has full HD screen (1920*1080) resolution. I use the Segoe UI font for text in most of the part of my application. I just solved the text blurriness issue by placing the Text block inside a Viewbox.

Here is the code of one my button which I use in my UI -

<Button
    x:Name="BtnSettings" Width="90" HorizontalAlignment="Left" Margin="200,14,0,0" Height="30" DockPanel.Dock="Left"
 VerticalAlignment="Top"  UseLayoutRounding="True"  RenderOptions.ClearTypeHint="Enabled"  RenderOptions.BitmapScalingMode="NearestNeighbor"   SnapsToDevicePixels="True"             
                           >
                <Button.Content >
                    <Viewbox Height="15" SnapsToDevicePixels="True"    x:Name="myViewbox"  Stretch="Uniform"  >
                        <TextBlock x:Name="myTextbox" FontSize="10" TextWrapping="Wrap"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"          FontFamily="Segoe UI" UseLayoutRounding="True" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"  TextOptions.TextFormattingMode="Display"       Margin="0,-2,0,0" TextOptions.TextRenderingMode="ClearType"  RenderOptions.ClearTypeHint="Enabled">

                Settings
                    </TextBlock>
                    </Viewbox>
                </Button.Content>                  
            </Button>

As you see from the code that I use the Segoe UI font size 10 and I scale it by Viewbox by just giving the height of the Viewbox until I get the desire size. My design is perfectly looking good that means no blurriness in text in my Primary Laptop (1920*1080) in which I develop the application but as soon as I change the screen resolution to any lower resolution like 1366*768 the text inside the Viewbox again looks blurry.

That means the Viewbox can not scale the child elements according to the screen DPI and resolution.

There is another decent reason that why I use the Viewbox? Actually in my application UI, some of the part I use the Segoe UI font size =10 and another part I use the Segoe UI font size = 8. The beauty of the Segoe UI font is, in every font size the letter look different from previous and the letter spacing is also different.

I just use Viewbox to get the text bigger without changing the font size.

I also use the ControlFontSize to scale my font size.

Here is the code -

double controlsize = ((SystemParameters.PrimaryScreenWidth / 12) / 3 * 2) / 5 * 0.7;
System.Windows.Application.Current.Resources.Remove("ControlFontSize");
System.Windows.Application.Current.Resources.Add("ControlFontSize", controlsize);

But the downside is it's only scale a single font size, as I say previously I use different screen font size through out my UI, I don't know how to use it on multiple Font size because this code can only put once in Window_Load event. and there is one window load event in every application.

People also told me to use the scale transformation instead of Viewbox. But the similar case happen again, as soon as I change the screen resolution the text became blurry again. Some people suggest me on Reddit that I should do some data binding to the Viewbox with my screen DPI so, that the Viewbox automatically scale it's child elements.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,757 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,829 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. DaisyTian-1203 11,621 Reputation points
    2021-06-16T06:23:19.697+00:00

    Microsoft provide a sample named Per Monitor Aware WPF sample , it is a WPF application updated to be per-monitor DPI-aware. You can download it and run it with the steps: Updating an existing WPF Application to be per-monitor dpi-aware using helper project in the WPF Sample.
    Its result picture is:
    106046-3.gif

    Did it work for you? If it doesn't, please let me know.


    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.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.