WPF : screen resolution independence with Perspective

WPF : screen resolution independence with Perspective

The unit of 2D WPF coordinate system is the Device Independent Pixel (DIP). It is a logical pixel, independent of the resolution of the display device : 96 DIP correspond to 1 inch (2.54 cm).

It is therefore easy to determine dimensions programmatically in physical units of measure, particularly in inches. For fans of the metric system, the Perspective library (from version 0.5) provides conversion functions in the DipHelper class : MmToDip(), CmToDip(), InchToDip(), DipToCm() and DipToMm().

It works fine for printing. But the on-screen display is much less obvious.

Indeed, the system does not know the size of the screen (his diagonal) and therefore can't know its actual points density.

Windows provides options for manually setting the points density. But its role is ambiguous, as it is presented to the user as a way to change the font size (and indirectly to apply a scaling factor to the whole system). This is made via the desktop context menu :

  • Under Windows 7 : Personalize - Display.
  • Under Windows Vista : Properties – Adjust font size (DPI).
  • Under Windows XP : Properties – Settings – Advanced.

Windows 7 DPI scaling setting

By default, Windows considers that the screen has a resolution of 96 dpi. This is true for a 17-inch flat screen with a 1280x1024 matrix, but wrong for a 19-inch with the same definition, and in many other cases... So generally, 96 DIP do not correspond to one inch!

Unless if you tell Windows the actual density of the screen, using the custom DPI setting - link Set custom text size (DPI) under Windows 7.

Windows 7 custom DPI scaling setting

The adjustment is done by dragging the displayed graduation until it corresponds to a ruler (in inches) put on the screen.

But an overall scaling is applied to the system, and some applications may encounter problems.

A solution is to make a scaling on the same principle but only at the WPF application level. The scaling factor to be applied may be determined in 2 ways with tools provided by the Perspective library :

  • DipHelper.GetScreenIndependentScaleFactor() determines that factor from the size of the diagonal of the screen, expressed in inches. This assumes that this size is known, and most importantly that it fits well the displayed surface (which is not always the case with cathodic screens).
  • The Ruler class displays a scale in centimeters ;-) (or in inches if you prefer). It can be used the same way as the Windows configuration, applying a scaling until its dimensions correspond to a ruler put on the screen. The obtained factor can then be used for a general scaling of the application (except for the setting screen, of course).

These 2 techniques are illustrated in the PerspectiveDemo application (page Pages/pWpf/DpiScaling.xaml, project PerspectiveDemo.UI).

Perspective DPI scaling

The ScreenSizeToScaleFactorConverter class (which uses DipHelper.GetScreenIndependentScaleFactor()) allows the binding of the scale factor to the input box of the screen diagonal size (itself linked to a Slider). See DpiScaling.xaml.

This application also illustrates the storage of scaling parameters in .NET Isolated Storage via AssemblyConfigManager class (which uses IsolatedStorageHelper).

private void bSaveScale_Click(object sender, RoutedEventArgs e)
{
    DipHelper.ScreenIndependentScaleX = ScreenIndependentScaleTransform.ScaleX;
    DipHelper.ScreenIndependentScaleY = ScreenIndependentScaleTransform.ScaleY;
    DipHelper.ScreenSize = sScreenSize.Value;
    AssemblyConfigManager.SaveSettings();
}

About this article

Author: Olivier Dewit.

History:

  • the 30th june, 2010 : update for the 0.9 version of Perspective, and for Windows 7.
  • the 16th may, 2008 : update for the 0.9 version of Perspective. Original article
  • January 6, 2008 : 1st publication (Perspective version 0.5). Original article