November 30, 2007

Clicking F1 on Width and Height properties in Visual Studio, it is written that the “value is interpreted as a device-independent unit (1/96th inch) measurement”.

Now, the default value of DPI (dots per inch) in a default Windows installation with a simple Monitor is 96. Now let’s calculate how many pixels you have: px = 100/96 * dpi ==> if dpi=96 then px=100, else, if dpi=120 then px=125.

What does it means?

It means that your UI will look much larger in DPI > 96 and much smaller in DPI < 96 under the same resolution!

Why it is said that WPF is device independent?

I can’t tell you the answer because I don’t know. Even if you choose to work with “cm” or “in”, first you will not get the correct size (measure it!), and second if you change the resolution the size will change also. So ask the WPF team to get the correct answer for that.

Still, I can give you tools to create a real DPI independent UI, in case that you must display exactly the same amount of pixels, no matter what the DPI is.

If you want pixels just recalculate the value using the formula:

finalPixels = desiredPixels * 96 / DPI

Use one of the following methods to calculate the final value dynamically via XAML (I prefer the second one):

6 comments

“Even if you choose to work with “cm” or “in”, first you will not get the correct size (measure it!), and second if you change the resolution the size will change also”

*If* your system is correctly configured, you will in fact get exactly the correct size. If you have a 120dpi screen and you configure Windows so that it *knows* you have a 120dpi screen, and you ask WPF to make something 5 inches across, it will be 5 inches across.

Of course, if you change the configured resolution, then unless you also go out and buy yourself a new monitor whose dpi matches the new dpi setting you just configured, the size will change. If you lie to Windows about the dpi of your monitor, then you can’t blame WPF for rendering things the wrong size. In order to render things at the correct size, WPF absolutely needs to know what the DPI of your monitor is. Without that information, how is it supposed to know how many pixels it needs to render in order to make something a particular size?

The point people often seem to miss is that Windows doesn’t magically know how big your screen is. If you disconnect a 17″ 1280×1024 monitor and replace it with a 19″ 1280×1024 monitor, obviously you now have larger pixels (i.e., a lower dpi), but Windows doesn’t know that. It only knows that you’ve still got a 1280×1024 screen in place.

Sadly, historically there has never been any way for the monitor to notify Windows of its DPI. This is partly because for years we used CRTs, and there’s not all that much variation in dpi from one CRT to another. Not compared with printers – printer resolutions range from 100dpi for dot matrix printers up to thousands of dpi for typesetting machines. Since the resolution of printers has always spanned orders of magnitude, they really had to solve the problem properly. The upshot of this is that printers always know *exactly* what their DPI is. But in the world of screens, this never happened, because it wasn’t as pressing a problem.

The monitor’s VGA cable doesn’t have a way of passing dpi information from the monitor back to the computer. And while doubtless DVI and HDMI could do this sort of thing, the problem is now one of inertia – Windows works like it always has. (And this is a problem for Macs too. It used to be a problem only if you fitted a non-Apple monitor, but now the latest PowerBooks come with pixels that are smaller than the Mac thinks they are. So Mac laptops get sizes wrong too.)

So Windows is totally and utterly dependent on that DPI setting – that’s the only information it has about how big the physical pixels on your screen are. And if you lie to it, of course it generates incorrect results.

The worst of it is that people have observed that providing Windows with incorrect DPI information has the side effect of changing how big everything looks, and so the DPI setting has frequently been abused as a sort of ‘size control’, which really isn’t what it’s designed for. This abuse has become so ingrained, that Vista even tells you this is what it does. So it’s difficult to see how Microsoft could ever get themselves out of this problem. Nonetheless, WPF uses this DPI setting as it was designed to be used, and not how it is popularly abused.

I think it’s compounded by the fact that the dialog suggests that you are changing the DPI of your screen. You’re not – you can’t do that. If you want a different DPI you need to get a different screen. The DPI is fixed – its determined by unchangeable physical characteristics of the screen: it’s the number of pixels across the screen divided by the width of the screen. For a flat panel, you can’t change either of those values. (For a CRT it’s more complex. The width is fixed, but you might be able to run with a number of different pixel counts. On a given CRT, the DPI at 1024×768 will be lower than at 1280×1024. But for given pixel dimensions, the dpi is fixed, because it is determined by the physical size of the screen.)

The DPI Scaling window doesn’t change the DPI of your screen. It changes what Windows *thinks* the DPI of your screen is.

(As an aside, if you’re using a projector, then you can change the DPI. The further away the projector is from the screen, the larger the image, and therefore, the lower the DPI. But usual reason for using a projector is to make the display much larger, so an incorrect DPI configuration turns out to be desirable. Otherwise, Windows would attempt to make, say, 16pt text really be 16pt, which would probably amount to 2 or 3 pixels…)

As for this:

“to create a real DPI independent UI, in case that you must display exactly the same amount of pixels, no matter what the DPI is”

*splutter* No no no! That’s the exact opposite of a DPI-independent UI.

Consider what it would mean if what you say were true. Suppose you render a 96 pixel button. If you display that on a screen that happens to have a 96 pixel per inch resolution, it’ll be one inch across. If you display 96 pixels on a 600dpi laser printer, it’ll be less than one sixth of an inch across.

If your image shrinks to one sixth of its size when the DPI goes up by a factor of six you emphatically do *not* have DPI-independence. The size of a 96-pixel element is totally dependent on the DPI of the device.

DPI independence means that you render things the right size regardless of DPI. So in the case of a 1 inch feature, that means using 96 pixels on a 96dpi screen, 144 pixels on a 144dpi screen, 600 pixels on a 600 dpi laser printer and so on. This is DPI independent because the feature ends up being 1 inch regardless of the DPI of the device.

Of course, you need to *know* the DPI of the device to make that work.

WPF is independent of device DPI in that it is able to render content at the correct size for any device DPI. The problematic part is that WPF depends on the device actually knowing it’s own DPI; in Windows, the screen does not know, unless you the user have correctly configured that DPI setting. The vast majority of the time, WPF is working with incorrect information. But given correct information, it behaves correctly.

I apologize if you missed my point. When I wrote “WPF is DPI Dependent” I meant to say that you wont get your required size unless…”. Also WPF can’t known or predict the nature resolution of your monitor. These are the reasons that WPF Is DPI Dependent, because Windows is.

The “if you will do this”, and “if you will do that” are not excuses. If you want to say WPF is Device independent, you must describe the exact technique or mode of action to achieve it.

I read several posts on this issue in the past, and I realized that only *if* you are working with the “Native Resolution” of your monitor you will get the correct size. I can even say that with CRT monitors, it is not enough to work with the “Native Resolution”, what if you change the Vertical and Horizontal settings of your screen, using the monitor menu?

Sadly, neither of these describe in the MSDN.

As for “to create a real DPI independent UI…”, you are right. I meant to say “in case that you must display exactly the same amount of pixels, no matter what the DPI is”.

@Ian Griffiths: I’ve never heard such a load of drivel in all my life.

Windows has been able to determine the physical DPI of a screen since Windows 95 days (some Windows 3.x apps could do it themselves). Even on old CRT monitors, the DDC (Display Data Channel) pins on the VGA connector have been able to deliver EDID (Extended Display IDentification) data to the host computer.

The EDID packet contains the physical height and width of the display area along with all of the resolutions it can display. It is trivial to determine the DPI for any given resolution from that data. Manufacturers who chose not to implement either DDC or EDID could still specify these things in an .INF file for their particular screen.

@VGA Guy: It’s a bit late, but still very interesting comment.
I’m not such a VGA expert, but what you’re saying is that you can determine what my hardware display DPI is?
Who can tell that, the display or the graphic card?
Can you specify a Windows API for retrieving such precious data?
Anyway, WPF is too old for that. There will be no changes in the future, I’m guessing 🙂

@Ian Griffiths :
Your answer makes more than 1 page on my screen.
What about keeping things simple when they could be simple ?
If I say I want an image or a button or anything 100 pixels by 100, I think WPF should allow me to have such a size, not more, not less, and without having to search among thousands of posts how to get this result.