DIUs, Not DUIs

In a previous post, I included a sample project to demonstrate how to make non-rectangular windows in WPF with Interop. You may or may not have noticed something like this in the code: ScaleUI.UpScaleX( someValue ), or ScaleUI.UpScaleY( someValue ). Admittedly, I stated in the comments to not worry about it, but in this post I will explain why that static class exists.

If you’re like most of the WinJing devs, you’ve come from the Win32/MFC world where you’ve been conditioned to think in terms of pixels. Coming to WPF, you (by “you” I really mean “myself”) probably would assume setting a window’s size and location would also be in pixel units.

And you’d be right. Sort of. In some cases.

What we, and I’m actually talking about myself, found out the hard way was that WPF does not perform sizing and placement in terms of pixels. Instead, WPF was designed to recognize placement and sizing in terms of what Microsoft engineers dubbed Device Independent Units.

Besides being a typical verbose Microsoft acronym, DIUs are actually not that complicated. To the WPF runtime, 1 DIU = 1/96 of an inch, or 96 dpi. So for example, if you sized a window to be 288 x 288, what you’re really saying is the window should be 3 in. x 3 in (96 x 3 = 288). The WPF architects did this so that applications written in WPF would be sized “correctly” on different monitors with different dimensions and resolutions. The implications of this are:

If your monitor is set to 96 dpi, the window’s width and height would map directly to pixel units.

A window should be relatively the same size on two monitors with different resolution settings.

WPF will scale your windows and elements automatically as best it can in terms of inches regardless of your dpi.

But beware, you can’t just use DIUs and forget about dpi totally. As well designed as WPF is, it is missing some functionality that WinForms, and even MFC/Win32 provides. For example, Jing’s Sun Launcher’s position is stored internally as a percentage of a screen’s width and height to avoid resolution issues. To get the current monitor’s size, we had to use the WinForms Screens API because WPF does not have the equivalent set of classes. However, the Screens classes work in terms of pixel sizes, but assumes the resolution is set to 96 dpi. For example, if a desktop’s size was set to 1280 x 1024 at 120 dpi, it should really be 1024 x 819, but the Screens API would report the monitor’s dimensions as 1280 x 1024 @ 96 dpi (120 / 96 = 120%, so everything is scaled up by 20%). Plus, if you have to use Interop (and chances are you will) like we did, you need to take the horizontal and vertical dpi into account when translating from DIUs to pixels.

One way to get the system’s dpi settings is with this line of code:

PresentationSource.FromVisual( Application.Current.MainWindow ).CompositionTarget.TransformToDevice;

However, because you need a window that’s already been loaded, we used Interop on Jing to call the GetDeviceCaps function to avoid that. This is what forms the basis of the ScaleUI class, which was used to take a monitor’s resolution into account.

Finally, don’t let the DIU acronym fool you. If you took a ruler to measure your WPF window, chances are it won’t be the exact size that you specified. The reason is because your monitor’s real, physical dpi is probably different from the resolution that is set in your Display Settings. In other words, WPF doesn’t know this real dpi, so it scales everything as best it can in terms of the dpi that you set in the Control Panel. Interestingly, if you set your dpi to match your monitor’s physical resolution, everything will be sized exactly as you specified.

In other words, what DIU really means is this: if you had two monitors, and each one had its dpi set to match its physical resolution, a window in WPF will be exactly the same size on both.

For more information on the implications of DIUs, read this excellent post by WPF Learning Experience. And if I had taken the two minutes to ask our lead developer about DIUs in the first place, all of this confusion would have been avoided..

Explore posts in the same categories: WPF

Tags: , , , ,

You can comment below, or link to this permanent URL from your own site.

Comment:

You must be logged in to post a comment.