Thomas Alva Edison's light bulb VBInfoZine Home
   An ordinary VB developer shares his own successes and failures
   FREE to registered subscribers.  

PageSetupDialog Margins Conversion Fix

A definitive cure for the PageSetupDialog margins conversion bug.

Recently, I've been adding printing capabilities to one of the WinForms applications I wrote some time ago. One of the standard printing-related features I was going to implement was the page setup dialog. It seemed to be a piece of cake with the help of the built-in System.Windows.Forms.PageSetupDialog component. Just assign it an instance of your PrintDocument-derived class and invoke the ShowDialog method:
Imports System.Drawing.Printing

Dim Doc As PrintDocument = New DataPrintDocument(...)
Dim Dlg As New PageSetupDialog
Dlg.Document = Doc
If Dlg.ShowDialog() = DialogResult.OK Then
  ' Save the page settings for later use when printing / previewing...
End If
It turns out that when you live in a region where a 'metric' measurement system is being used, the PageSetupDialog class exposes a known conversion bug (see the MS KB article).

I've Googled a bit (searched for "PageSetupDialog metric" on Google Groups) and I was able to find a solution to the problem - just convert the page margins to millimeters before displaying the dialog:
If System.Globalization.RegionInfo.CurrentRegion.IsMetric Then
  dlg.Document.DefaultPageSettings.Margins = _
    PrinterUnitConvert.Convert(dlg.Document.DefaultPageSettings.Margins, _
      PrinterUnit.Display, PrinterUnit.TenthsOfAMillimeter)
End If
However, there are two problems with this approach:

First, the workaround should have been better encapsulated, because when MS releases a fix to the problem, we'll have to "fix our fix" once again. If we'd like to avoid recompilation, the fix must be controlled externally, preferably by a setting in the application's configuration file.

Second, the System.Globalization.RegionInfo.CurrentRegion.IsMetric property returns the metric setting for the whole region; it ignores what the user might have specified in the Regional Options control panel applet for the 'Measurement system' setting. That is, you can have US measurement system active even if you have metric region selected, and vice versa.

In order to solve the problems, I've encapsulated the fix in a simple PageSetupDialogHelper class. Its usage is very simple - just add the PageSetupDialogHelper.vb file to your project and then, instead of calling the PageSetupDialog.ShowDialog instance method, call the PageSetupDialogHelper.ShowDialog shared method passing it the PageSetupDialog instance as an argument:
Dim Doc As PrintDocument = New DataPrintDocument(...)
Dim Dlg As New PageSetupDialog
Dlg.Document = Doc
If PageSetupDialogHelper.ShowDialog(Dlg) = DialogResult.OK Then
  ' Save the page settings for later use when printing / previewing...
End If
The PageSetupDialogHelper class correctly handles the 'Measurement system' setting (by using P/Invoke, not directly reading the Control Panel's international registry keys as one of the other solutions implemented). If Microsoft fixes the bug sometime in the future, you can bypass the PageSetupDialogHelper's workaround by adding the following key to your application config file (under the <appSettings> section):
<add key="ApplyPageSetupDialogFix" value="no" />
Here is a VB.NET demo project containing the PageSetupDialogHelper class.

Enjoy!

(c) Palo Mraz, Friday, April 23, 2004
 ©2003-2008 Palo Mraz. All Rights Reserved.   See my 'new browser window' policy