Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0153: Bug im PageSetupDialog

 von 

Beschreibung

In Windows-Systemen mit metrischem Maßsystem in den Regions- und Spracheinstellungen kommt es zu zwei Fehlern bei der Benutzung des PageSetupDialog:

  1. Ist EnableMetric nicht gesetzt, werden falsche Werte für die Seitenränder zurückgeliefert, da immer davon ausgegangen wird, dass die Zahlen metrische Werte sind, was allerdings in dem Fall nicht gegeben ist. Somit werden zum Beispiel aus 100 1/100 Inch plötzlich 39 1/100 Inch.
  2. Ist EnableMetric auf True gesetzt werden die Werte für die Seitenränder teilweise falsch angezeigt. Das liegt daran, dass die Werte in der Margins-Klasse als Integer definiert sind und es bei der Umrechnung von Inch in Millimeter zu gewaltigen Rundungsfehlern kommt.
    Dieser Fehler ist Microsoft sehr wohl bekannt, sie bieten aber keinen wirklich praktikablen Workaround dazu an (KB814355).
Mit einem kleinen Trick ist es möglich zumindest mit vollen Millimeterwerten korrekt zu arbeiten. Der Trick: EnableMetric auf False setzen und die Werte für die Seitenränder in metrische Werte umrechnen bevor der Dialog aufgerufen wird. Nachkommastellen können aufgrund der Auslegung als Integer leider nicht berücksichtigt werden, was für die meisten Anwendungen allerdings vollkommen ausreichend sein sollte.
Wird eine höhere Auflösung benötigt führt kein Weg an einem eigenen Dialog und eigenen Pagesettings- und Margins-Klassen vorbei.
Hier finden sich beide Lösungsmöglichkeiten.

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Framework-Version(en):

.NET Framework 1.0, .NET Framework 1.1, .NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5, .NET Framework 4

.NET-Version(en):

Visual Basic 2002, Visual Basic 2003, Visual Basic 2005, Visual Basic 2008, Visual Basic 2010

Download:

Download des Beispielprojektes [29,63 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2008
' Option Strict:    An
' Option Explicit:  An
' Option Infer:     An
'
' Referenzen: 
'  - System
'  - System.Data
'  - System.Deployment
'  - System.Drawing
'  - System.Management
'  - System.Windows.Forms
'  - System.Xml
'
' Imports: 
'  - Microsoft.VisualBasic
'  - System
'  - System.Collections
'  - System.Collections.Generic
'  - System.ComponentModel
'  - System.Drawing
'  - System.Diagnostics
'  - System.Windows.Forms
'  - System.Xml.Serialization
'

' ##############################################################################
' ########################## dlgMyPageSetupDialog.vb ###########################
' ##############################################################################
Imports System.Windows.Forms

Public Class dlgMyPageSetupDialog

    Private _pagesettings As MyPageSettings
    Private _printersettings As Printing.PrinterSettings
    Private _EnableMetric As Boolean
    Private _PreviewText As String = _
        "Dies ein Test für die Seiteneinstellungen ihres Druckers." & _
        vbCrLf & "Doch manchmal ist einfach zu blöd einen sinnvollen Text " & _
        "für sowas zu erstellen daher lassen wird das jetzt und geben den " & _
        "Text einfach mal aus." & vbCrLf & vbCrLf

    Public Property PageSettings() As MyPageSettings
        Get
            Return _pagesettings
        End Get
        Set(ByVal value As MyPageSettings)
            _pagesettings = value
            _printersettings = _pagesettings.PrinterSettings
        End Set
    End Property

    Public Property PrinterSettings() As Printing.PrinterSettings
        Get
            Return _printersettings
        End Get
        Set(ByVal value As Printing.PrinterSettings)
            _printersettings = value
        End Set
    End Property

    Public Property EnableMetric() As Boolean
        Get
            Return _EnableMetric
        End Get
        Set(ByVal value As Boolean)
            _enableMetric = value
        End Set
    End Property

    Private Sub btnOk_Click(ByVal sender As System.Object, _
                            ByVal e As System.EventArgs) Handles btnOk.Click
        CreateNewPageSettings()
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub

    Private Sub btnCancel_Click(ByVal sender As System.Object, _
                                ByVal e As System.EventArgs) _
                            Handles btnCancel.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
        Me.Close()
    End Sub

    Private Sub btnPrinter_Click(ByVal sender As System.Object, _
                                 ByVal e As System.EventArgs) _
                             Handles btnPrinter.Click
        Dim dlgprn As New dlgMyPrinterSettings
        dlgprn.PrinterSettings = _printersettings
        If dlgprn.ShowDialog = Windows.Forms.DialogResult.OK Then
            _printersettings = dlgprn.PrinterSettings
            _pagesettings = New MyPageSettings(_printersettings)
            ShowPageSettings()
        End If
    End Sub

    Private Sub ShowPageSettings()
        pnlPreview.SuspendLayout()
        cbxPaperSize.Items.Clear()
        For Each ps As Printing.PaperSize In _
                _pagesettings.PrinterSettings.PaperSizes
            cbxPaperSize.Items.Add(ps.PaperName)
        Next
        cbxPaperSize.SelectedItem = _pagesettings.PaperSize.PaperName
        cbxPaperSource.Items.Clear()
        If _printersettings.PaperSources.Count > 0 Then
            For Each ps As Printing.PaperSource In _printersettings.PaperSources
                cbxPaperSource.Items.Add(ps.SourceName)
            Next
            cbxPaperSource.SelectedItem = _pagesettings.PaperSource.SourceName
            cbxPaperSource.Enabled = True
        Else
            cbxPaperSource.Enabled = False
        End If
        If _pagesettings.Landscape Then
            rbtLandscape.Checked = True
        Else
            rbtNormal.Checked = True
        End If
        If Globalization.RegionInfo.CurrentRegion.IsMetric And _EnableMetric Then
            txtMarginLeft.Text = Math.Round( _
                _pagesettings.Margins.LeftMetric / 10, 2).ToString
            txtMarginRight.Text = Math.Round( _
                _pagesettings.Margins.RightMetric / 10, 2).ToString
            txtMarginTop.Text = Math.Round( _
                _pagesettings.Margins.TopMetric / 10, 2).ToString
            txtMarginBottom.Text = Math.Round( _
                _pagesettings.Margins.BottomMetric / 10, 2).ToString
        Else
            txtMarginLeft.Text = Math.Round( _
                _pagesettings.Margins.Left / 10, 2).ToString
            txtMarginRight.Text = Math.Round( _
                _pagesettings.Margins.Right / 10, 2).ToString
            txtMarginTop.Text = Math.Round( _
                _pagesettings.Margins.Top / 10, 2).ToString
            txtMarginBottom.Text = Math.Round( _
                _pagesettings.Margins.Bottom / 10, 2).ToString
        End If
        pnlPreview.ResumeLayout()
    End Sub

    Private Function PaperSizeFromName(ByVal Name As String) _
            As Printing.PaperSize
        For Each ps As Printing.PaperSize In _printersettings.PaperSizes
            If ps.PaperName = Name Then
                Return ps
            End If
        Next
        Return Nothing
    End Function

    Private Function PaperSourceFromName(ByVal Name As String) _
            As Printing.PaperSource
        For Each ps As Printing.PaperSource In _printersettings.PaperSources
            If ps.SourceName = Name Then
                Return ps
            End If
        Next
        Return Nothing
    End Function

    Private Sub CreateNewPagesettings()
        _pagesettings = New MyPageSettings
        _pagesettings.PrinterSettings = _printersettings
        Dim tmp As Single = 0.0
        If Globalization.RegionInfo.CurrentRegion.IsMetric And _EnableMetric Then
            Single.TryParse(txtMarginLeft.Text.Trim, tmp)
            _pagesettings.Margins.LeftMetric = CSng(Math.Round(tmp * 10, 2))
            Single.TryParse(txtMarginRight.Text.Trim, tmp)
            _pagesettings.Margins.RightMetric = CSng(Math.Round(tmp * 10, 2))
            Single.TryParse(txtMarginTop.Text.Trim, tmp)
            _pagesettings.Margins.TopMetric = CSng(Math.Round(tmp * 10, 2))
            Single.TryParse(txtMarginBottom.Text.Trim, tmp)
            _pagesettings.Margins.BottomMetric = CSng(Math.Round(tmp * 10, 2))
        Else
            Single.TryParse(txtMarginLeft.Text.Trim, tmp)
            _pagesettings.Margins.Left = CSng(Math.Round(tmp * 10, 2))
            Single.TryParse(txtMarginRight.Text.Trim, tmp)
            _pagesettings.Margins.Right = CSng(Math.Round(tmp * 10, 2))
            Single.TryParse(txtMarginTop.Text.Trim, tmp)
            _pagesettings.Margins.Top = CSng(Math.Round(tmp * 10, 2))
            Single.TryParse(txtMarginBottom.Text.Trim, tmp)
            _pagesettings.Margins.Bottom = CSng(Math.Round(tmp * 10, 2))
        End If
        _pagesettings.Landscape = rbtLandscape.Checked
        If cbxPaperSource.Enabled Then
            _pagesettings.PaperSource = _
                PaperSourceFromName(cbxPaperSource.SelectedItem.ToString)
        Else
            _pagesettings.PaperSource = Nothing
        End If
        _pagesettings.PaperSize = _
            PaperSizeFromName(cbxPaperSize.SelectedItem.ToString)
    End Sub

    Private Sub dlgMyPageSetupDialog_Load(ByVal sender As Object, _
                                          ByVal e As System.EventArgs) _
                                      Handles Me.Load
        ShowPageSettings()
    End Sub

    Private Sub pnlPreview_Paint(ByVal sender As Object, _
            ByVal e As System.Windows.Forms.PaintEventArgs) _
            Handles pnlPreview.Paint

        Dim docrect As Rectangle = TransformInchToDevice(e.Graphics, _
                                                         _pagesettings.Bounds)
        Dim marrect As Rectangle = TransformInchToDevice(e.Graphics, _
                                                         _pagesettings.Margins)
        Dim fkt As Double
        If _pagesettings.Landscape Then
            fkt = docrect.Width / (pnlPreview.Width - 10)
        Else
            fkt = docrect.Height / (pnlPreview.Height - 10)
        End If
        docrect.Width = CInt(Math.Round(docrect.Width / fkt))
        docrect.Height = CInt(Math.Round(docrect.Height / fkt))
        marrect.X = CInt(Math.Round(marrect.X / fkt))
        marrect.Y = CInt(Math.Round(marrect.Y / fkt))
        marrect.Width = CInt(Math.Round(marrect.Width / fkt))
        marrect.Height = CInt(Math.Round(marrect.Height / fkt))
        Dim offset As Size = New Size(8, 8)
        If _pagesettings.Landscape Then
            docrect.Location = New Point(0, _
                CInt((pnlPreview.Height - 8 - docrect.Height) / 2) - 3)
        Else
            docrect.Location = New Point( _
                CInt((pnlPreview.Width - 8 - docrect.Width) / 2) - 3, 0)
        End If
        marrect.Size = New Size(docrect.Width - marrect.X - marrect.Width, _
                                docrect.Height - marrect.Y - marrect.Height)
        marrect.Location = New Point(marrect.X + docrect.X, _
                                     marrect.Y + docrect.Y)
        Dim br As Brush = New SolidBrush(SystemColors.ButtonShadow)
        e.Graphics.FillRectangle(br, _
            New Rectangle(docrect.Location + offset, docrect.Size))
        br = New SolidBrush(Color.White)
        e.Graphics.FillRectangle(br, docrect)
        Dim pn As New Pen(Color.Black)
        e.Graphics.DrawRectangle(pn, docrect)
        pn = New Pen(Color.Silver)
        pn.DashStyle = Drawing2D.DashStyle.Dash
        e.Graphics.DrawRectangle(pn, marrect)
        marrect.Location = marrect.Location + New Size(1, 1)
        marrect.Size = marrect.Size - New Size(2, 2)
        Dim ptxt As String = _PreviewText & _PreviewText & _PreviewText & _
            _PreviewText & _PreviewText & _PreviewText & _
            _PreviewText & _PreviewText & _PreviewText
        e.Graphics.DrawString(ptxt, New Font(New FontFamily("Arial"), 3), _
                              New SolidBrush(Color.Black), marrect)
    End Sub

    Private Function TransformInchToDevice(ByVal gr As Graphics, _
                                           ByVal value As PointF) As Point
        Dim pt() As PointF = {value}
        gr.PageUnit = GraphicsUnit.Inch
        gr.TransformPoints(Drawing2D.CoordinateSpace.Device, _
                           Drawing2D.CoordinateSpace.Page, pt)
        Return New Point(CInt(Math.Round(pt(0).X)), CInt(Math.Round(pt(0).Y)))
    End Function

    Private Function TransformInchToDevice(ByVal gr As Graphics, _
            ByVal value As RectangleF) As Rectangle

        Dim pt() As PointF = { _
            New PointF(value.Location.X / 100, value.Location.Y / 100), _
            New PointF(value.Size.Width / 100, value.Size.Height / 100)}
        gr.PageUnit = GraphicsUnit.Inch
        gr.TransformPoints(Drawing2D.CoordinateSpace.Device, _
                           Drawing2D.CoordinateSpace.Page, pt)
        gr.PageUnit = GraphicsUnit.Pixel
        Return New Rectangle(CInt(Math.Round(pt(0).X)), _
                             CInt(Math.Round(pt(0).Y)), _
                             CInt(Math.Round(pt(1).X)), _
                             CInt(Math.Round(pt(1).Y)))
    End Function

    Private Function TransformInchToDevice(ByVal gr As Graphics, _
            ByVal value As MyMargins) As Rectangle

        Dim pt() As PointF = {New PointF(value.Left / 100, value.Top / 100), _
                              New PointF(value.Right / 100, value.Bottom / 100)}
        gr.PageUnit = GraphicsUnit.Inch
        gr.TransformPoints(Drawing2D.CoordinateSpace.Device, _
                           Drawing2D.CoordinateSpace.Page, pt)
        gr.PageUnit = GraphicsUnit.Pixel
        Return New Rectangle(CInt(Math.Round(pt(0).X)), _
                             CInt(Math.Round(pt(0).Y)), _
                             CInt(Math.Round(pt(1).X)), _
                             CInt(Math.Round(pt(1).Y)))
    End Function

    Private Sub cbxPaperSize_SelectedIndexChanged(ByVal sender As Object, _
            ByVal e As System.EventArgs) _
        Handles cbxPaperSize.SelectedIndexChanged

        _pagesettings.PaperSize = _
            PaperSizeFromName(cbxPaperSize.SelectedItem.ToString)
        pnlPreview.Invalidate()
    End Sub

    Private Sub rbtLandscape_CheckedChanged(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles rbtLandscape.CheckedChanged

        _pagesettings.Landscape = rbtLandscape.Checked
        pnlPreview.Invalidate()
    End Sub

    Private Sub txtMarginBottom_TextChanged(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles txtMarginBottom.TextChanged

        Dim tmp As Single
        Single.TryParse(txtMarginBottom.Text.Trim, tmp)
        If Globalization.RegionInfo.CurrentRegion.IsMetric And _EnableMetric Then
            _pagesettings.Margins.BottomMetric = CSng(Math.Round(tmp * 10, 2))
        Else
            _pagesettings.Margins.Bottom = CSng(Math.Round(tmp * 10, 2))
        End If
        pnlPreview.Invalidate()
    End Sub

    Private Sub txtMarginLeft_TextChanged(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles txtMarginLeft.TextChanged

        Dim tmp As Single
        Single.TryParse(txtMarginLeft.Text.Trim, tmp)
        If Globalization.RegionInfo.CurrentRegion.IsMetric And _EnableMetric Then
            _pagesettings.Margins.LeftMetric = CSng(Math.Round(tmp * 10, 2))
        Else
            _pagesettings.Margins.Left = CSng(Math.Round(tmp * 10, 2))
        End If
        pnlPreview.Invalidate()
    End Sub

    Private Sub txtMarginRight_TextChanged(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles txtMarginRight.TextChanged

        Dim tmp As Single
        Single.TryParse(txtMarginRight.Text.Trim, tmp)
        If Globalization.RegionInfo.CurrentRegion.IsMetric And _EnableMetric Then
            _pagesettings.Margins.RightMetric = CSng(Math.Round(tmp * 10, 2))
        Else
            _pagesettings.Margins.Right = CSng(Math.Round(tmp * 10, 2))
        End If
        pnlPreview.Invalidate()
    End Sub

    Private Sub txtMarginTop_TextChanged(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles txtMarginTop.TextChanged

        Dim tmp As Single
        Single.TryParse(txtMarginTop.Text.Trim, tmp)
        If Globalization.RegionInfo.CurrentRegion.IsMetric And _EnableMetric Then
            _pagesettings.Margins.TopMetric = CSng(Math.Round(tmp * 10, 2))
        Else
            _pagesettings.Margins.Top = CSng(Math.Round(tmp * 10, 2))
        End If
        pnlPreview.Invalidate()
    End Sub
End Class

' ##############################################################################
' ########################## dlgMyPrinterSettings.vb ###########################
' ##############################################################################
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Management

Public Class dlgMyPrinterSettings

    Private Declare Function OpenPrinter Lib "winspool.drv" _
        Alias "OpenPrinterA" (ByVal pPrinterName As String, _
                              ByRef phPrinter As IntPtr, _
                              ByVal pDefault As IntPtr) As Int32
    Private Declare Function PrinterProperties Lib "winspool.drv" ( _
        ByVal hWnd As IntPtr, ByVal hPrinter As IntPtr) As Int32
    Private Declare Function ClosePrinter Lib "winspool.drv" ( _
        ByVal hPrinter As IntPtr) As Int32

    Private Enum PrinterStatus
        Sonstiger = 1
        Unbekannt = 2
        Bereit = 3
        Druckt = 4
        Aufwärmen = 5
        Angehalten = 6
        Offline = 7
    End Enum

    Private _PrinterSettings As Printing.PrinterSettings

    Public Sub New()

        ' Dieser Aufruf ist für den Windows Form-Designer erforderlich.
        InitializeComponent()

        ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf 
        '  hinzu.
        For Each s As String In Printing.PrinterSettings.InstalledPrinters
            cbxPrintername.Items.Add(s)
        Next
    End Sub

    Public Property PrinterSettings() As Printing.PrinterSettings
        Get
            Return _PrinterSettings
        End Get
        Set(ByVal value As Printing.PrinterSettings)
            _PrinterSettings = DirectCast(value.Clone, Printing.PrinterSettings)
            cbxPrintername.SelectedItem = _PrinterSettings.PrinterName
        End Set
    End Property

    Private Sub btnOK_Click(ByVal sender As System.Object, _
                            ByVal e As System.EventArgs) Handles btnOK.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub

    Private Sub btnCancel_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnCancel.Click

        Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
        Me.Close()
    End Sub

    Private Sub cbxPrintername_SelectedIndexChanged( _
            ByVal sender As Object, _
            ByVal e As System.EventArgs) _
            Handles cbxPrintername.SelectedIndexChanged

        _PrinterSettings.PrinterName = cbxPrintername.SelectedItem.ToString
        ShowPrinterStatus()
    End Sub

    Private Sub ShowPrinterStatus()
        Dim sQuery As String = "SELECT * FROM Win32_Printer WHERE Caption='" & _
            _PrinterSettings.PrinterName & "'"
        Dim Printerssearch As New ManagementObjectSearcher(sQuery)
        Dim printers As ManagementObjectCollection = Printerssearch.Get
        Dim prtcapt As String
        For Each prt As ManagementObject In printers
            prtcapt = prt.GetPropertyValue("Caption").ToString
            If prtcapt = _PrinterSettings.PrinterName Then
                lblStatus.Text = ""
                lblTyp.Text = ""
                lblLocation.Text = ""
                lblComment.Text = ""
                For Each prop As PropertyData In prt.Properties
                    Select Case prop.Name
                        Case "PrinterStatus"
                            If prop.Value IsNot Nothing Then
                                lblStatus.Text = DirectCast(CInt(prop.Value),  _
                                    PrinterStatus).ToString
                            End If
                        Case "DriverName"
                            If prop.Value IsNot Nothing Then
                                lblTyp.Text = prop.Value.ToString
                            End If
                        Case "PortName"
                            If prop.Value IsNot Nothing Then
                                lblLocation.Text = prop.Value.ToString
                            End If
                        Case "Comment"
                            If prop.Value IsNot Nothing Then
                                lblComment.Text = prop.Value.ToString
                            End If
                    End Select
                Next
            End If
        Next
    End Sub

    Private Sub btnPrinterProperties_Click(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles btnPrinterProperties.Click
        Dim hPrinter As IntPtr
        Dim retval As Int32

        retval = OpenPrinter(cbxPrintername.SelectedItem.ToString, _
                             hPrinter, Nothing)
        retval = PrinterProperties(Me.Handle, hPrinter)
        retval = ClosePrinter(hPrinter)
    End Sub

End Class

' ##############################################################################
' ############################### frmPSDBug.vb #################################
' ##############################################################################
Imports System.Drawing.Printing

Public Class frmPSDBug

    Private _PageSettings As Printing.PageSettings
    Private _PrinterSettings As PrinterSettings
    Private _myPageSettings As MyPageSettings

    Private Sub Form1_Load(ByVal sender As Object, _
                           ByVal e As System.EventArgs) Handles Me.Load
        _PrinterSettings = GetDefaultPrinterSettings()
        _PageSettings = _PrinterSettings.DefaultPageSettings
        _myPageSettings = New MyPageSettings(_PrinterSettings)
    End Sub

    Private Sub btnPageSetup_Click(ByVal sender As Object, _
                                   ByVal e As System.EventArgs) _
                               Handles btnPageSetup.Click

        If rbtOwnDialog.Checked Then
            Dim pdlg As New MyPageSetupDialog
            pdlg.EnableMetric = ckbMetric.Checked
            pdlg.PageSettings = _myPageSettings
            ShowMyMargins(pdlg.PageSettings.Margins, False)
            If pdlg.ShowDialog() = Windows.Forms.DialogResult.OK Then
                _myPageSettings = pdlg.PageSettings
            End If
            ShowMyMargins(_myPageSettings.Margins, True)
        Else
            Dim pdlg As New PageSetupDialog

            ShowMargins(_PageSettings.Margins, False)

            ' alte Seitenränder merken
            Dim oldMargins As Printing.Margins = _
                DirectCast(_PageSettings.Margins.Clone, Printing.Margins)

            ' mit Korrektur
            If rbtCorrection.Checked Then
                CorrectMargins(_PageSettings)
            End If

            ' PageSetupDialog initialisieren
            pdlg.PrinterSettings = _PrinterSettings
            pdlg.PageSettings = _PageSettings
            pdlg.EnableMetric = ckbMetric.Checked

            ' und los geht's
            If pdlg.ShowDialog() = Windows.Forms.DialogResult.OK Then
                ' Geänderte Seiteneinstellungen übernehmen
                _PageSettings = pdlg.PageSettings
            Else
                ' Bei Abbruch die nicht "korrigierten" Seitenränder wieder 
                '  zurück schreiben
                If rbtCorrection.Checked Then
                    _PageSettings.Margins = oldMargins
                End If
            End If

            ShowMargins(pdlg.PageSettings.Margins, True)
        End If
    End Sub

    Private Sub CorrectMargins(ByRef pgs As Printing.PageSettings)
        If Globalization.RegionInfo.CurrentRegion.IsMetric Then
            ' Wegen Rundungsfehlern darf nicht durch 0.3948 geteilt werden!
            Dim fkt As Single = 3.948
            pgs.Margins.Left = CInt(Math.Round(pgs.Margins.Left / fkt) * 10)
            pgs.Margins.Top = CInt(Math.Round(pgs.Margins.Top / fkt) * 10)
            pgs.Margins.Right = CInt(Math.Round(pgs.Margins.Right / fkt) * 10)
            pgs.Margins.Bottom = CInt(Math.Round(pgs.Margins.Bottom / fkt) * 10)
        End If
    End Sub

    Private Function GetDefaultPrinterSettings() As Printing.PrinterSettings
        Dim prs As New Printing.PrinterSettings
        For Each prtn As String In Printing.PrinterSettings.InstalledPrinters
            prs.PrinterName = prtn
            If prs.IsDefaultPrinter Then
                Return prs
            End If
        Next
        Return Nothing
    End Function

    Private Sub ShowMargins(ByVal vMargins As Printing.Margins, _
                            ByVal after As Boolean)
        If after Then
            lblALeft.Text = vMargins.Left.ToString()
            lblATop.Text = vMargins.Top.ToString()
            lblARight.Text = vMargins.Right.ToString()
            lblABottom.Text = vMargins.Bottom.ToString()
        Else
            lblBLeft.Text = vMargins.Left.ToString()
            lblBTop.Text = vMargins.Top.ToString()
            lblBRight.Text = vMargins.Right.ToString()
            lblBBottom.Text = vMargins.Bottom.ToString()
        End If
    End Sub

    Private Sub ShowMyMargins(ByVal vMargins As MyMargins, _
                              ByVal after As Boolean)
        If after Then
            lblALeft.Text = vMargins.Left.ToString()
            lblATop.Text = vMargins.Top.ToString()
            lblARight.Text = vMargins.Right.ToString()
            lblABottom.Text = vMargins.Bottom.ToString()
        Else
            lblBLeft.Text = vMargins.Left.ToString()
            lblBTop.Text = vMargins.Top.ToString()
            lblBRight.Text = vMargins.Right.ToString()
            lblBBottom.Text = vMargins.Bottom.ToString()
        End If
    End Sub

    Private Sub rbtCorrection_CheckedChanged(ByVal sender As Object, _
                                             ByVal e As System.EventArgs) _
                                         Handles rbtCorrection.CheckedChanged
        If rbtCorrection.Checked Then
            ckbMetric.Checked = False
            ckbMetric.Enabled = False
        Else
            ckbMetric.Enabled = True
        End If
    End Sub
End Class
' ##############################################################################
' ############################### MyMargins.vb #################################
' ##############################################################################
Imports System.ComponentModel
Imports System.Xml.Serialization

<SerializableAttribute()> _
<TypeConverterAttribute(GetType(MyMarginsConverter))> _
Public Class MyMargins
    Implements ICloneable

    Public Enum Units
        HundredsOfAnInch = 0
        TensOfAMillimeter = 1
    End Enum

    Private _Left As Single
    Private _Right As Single
    Private _Top As Single
    Private _Bottom As Single
    Private _Unit As Units = Units.HundredsOfAnInch

    Public Sub New()
    End Sub

    Public Sub New(ByVal left As Single, ByVal right As Single, _
                   ByVal top As Single, ByVal bottom As Single)
        _Left = Math.Abs(left)
        _Right = Math.Abs(right)
        _Top = Math.Abs(top)
        _Bottom = Math.Abs(bottom)
    End Sub

    Public Sub New(ByVal margins As Printing.Margins)
        _Left = margins.Left
        _Right = margins.Right
        _Top = margins.Top
        _Bottom = margins.Bottom
    End Sub

    Public Property Left() As Single
        Get
            Return _Left
        End Get
        Set(ByVal value As Single)
            _Left = Math.Abs(value)
        End Set
    End Property

    Public Property Right() As Single
        Get
            Return _Right
        End Get
        Set(ByVal value As Single)
            _Right = Math.Abs(value)
        End Set
    End Property

    Public Property Top() As Single
        Get
            Return _Top
        End Get
        Set(ByVal value As Single)
            _Top = Math.Abs(value)
        End Set
    End Property

    Public Property Bottom() As Single
        Get
            Return _Bottom
        End Get
        Set(ByVal value As Single)
            _Bottom = Math.Abs(value)
        End Set
    End Property

    <xmlignore()> _
    Public Property LeftMetric() As Single
        Get
            Return InchToMetric(_Left)
        End Get
        Set(ByVal value As Single)
            _Left = MetricToInch(Math.Abs(value))
        End Set
    End Property

    <XmlIgnore()> _
    Public Property RightMetric() As Single
        Get
            Return InchToMetric(_Right)
        End Get
        Set(ByVal value As Single)
            _Right = MetricToInch(Math.Abs(value))
        End Set
    End Property

    <XmlIgnore()> _
    Public Property TopMetric() As Single
        Get
            Return InchToMetric(_Top)
        End Get
        Set(ByVal value As Single)
            _Top = MetricToInch(Math.Abs(value))
        End Set
    End Property

    <XmlIgnore()> _
    Public Property BottomMetric() As Single
        Get
            Return InchToMetric(_Bottom)
        End Get
        Set(ByVal value As Single)
            _Bottom = MetricToInch(Math.Abs(value))
        End Set
    End Property

    Private Function MetricToInch(ByVal value As Single) As Single
        Return CSng(Math.Round(value * 3.937 / 10, 2))
    End Function

    Private Function InchToMetric(ByVal value As Single) As Single
        Return CSng(Math.Round(value / 3.937 * 10, 2))
    End Function

    Public Function Clone() As Object Implements System.ICloneable.Clone
        Dim cln As New MyMargins
        cln.Left = _Left
        cln.Right = _Right
        cln.Top = _Top
        cln.Bottom = _Bottom
        Return cln
    End Function

    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        If obj.GetType.Name = "MyMargins" Then
            Dim vo As MyMargins = DirectCast(obj, MyMargins)
            If vo.Left = _Left AndAlso vo.Right = _Right _
                AndAlso vo.Top = _Top AndAlso vo.Bottom = _Bottom Then
                Return True
            End If
        End If
        Return False
    End Function

End Class

' ##############################################################################
' ########################### MyMarginsConverter.vb ############################
' ##############################################################################
Imports System.ComponentModel

Public Class MyMarginsConverter
    Inherits ExpandableObjectConverter

    Public Sub New()
        MyBase.New()
    End Sub

  Public Overrides Function CanConvertFrom (_
            ByVal context As System.ComponentModel.ITypeDescriptorContext, _
                ByVal sourceType As System.Type) As Boolean

        If sourceType Is GetType(MyMargins) Then
            Return True
        ElseIf sourceType Is GetType(String) Then
            Return True
        Else
            Return MyBase.CanConvertFrom(sourceType)
        End If
    End Function

    Public Overrides Function CanConvertTo( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext, _
            ByVal destinationType As System.Type) As Boolean

        If destinationType Is GetType(String) Then
            Return True
        End If
    End Function

    Public Overrides Function ConvertFrom( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext, _
            ByVal culture As System.Globalization.CultureInfo, _
            ByVal value As Object) As Object

        If TypeOf value Is Printing.Margins Then
            Return New MyMargins(DirectCast(value, Printing.Margins))
        ElseIf TypeOf value Is String Then
            Return ObjectFromString(DirectCast(value, String), culture)
        End If
        Return MyBase.ConvertFrom(context, culture, value)
    End Function

    Public Overrides Function ConvertTo( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext, _
            ByVal culture As System.Globalization.CultureInfo, _
            ByVal value As Object, _
            ByVal destinationType As System.Type) As Object

        If destinationType Is GetType(String) Then
            Dim src As MyMargins = DirectCast(value, MyMargins)
            Dim retval As String = "{MyMargins"
            retval &= " Left=" & src.Left.ToString("g", culture)
            retval &= " Right=" & src.Right.ToString("g", culture)
            retval &= " Top=" & src.Top.ToString("g", culture)
            retval &= " Bottom=" & src.Bottom.ToString("g", culture)
            Return retval
        End If
        Return MyBase.ConvertTo(context, culture, value, destinationType)
    End Function

    Public Overloads Function IsValid(ByVal value As Object) As Boolean
        If TypeOf value Is String Then
            Dim v As String = DirectCast(value, String)
            Return v.StartsWith("{MyMargins") And _
                v.Contains("Left=") And _
                v.Contains("Right=") And _
                v.Contains("Top=") And _
                v.Contains("Bottom=")
        ElseIf TypeOf value Is Printing.Margins Then
            Return True
        Else
            Return MyBase.IsValid(value)
        End If
    End Function

    Public Overrides Function IsValid( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext, _
            ByVal value As Object) As Boolean

        Return IsValid(value)
    End Function

    Private Function ObjectFromString(ByVal value As String, _
            ByVal culture As Globalization.CultureInfo) As MyMargins

        Dim v As String() = _
            value.Replace("{", "").Replace("}", "").Split(New Char() {" "c})
        Dim mm As New MyMargins
        If v(0).Trim <> "MyMargins" Then
            Return Nothing
        End If
        For Each s As String In v
            If s.StartsWith("Left=") Then
                Single.TryParse(s.Substring(s.IndexOf("=") + 1), _
                    System.Globalization.NumberStyles.AllowDecimalPoint, _
                    culture, mm.Left)
            End If
            If s.StartsWith("Right=") Then
                Single.TryParse(s.Substring(s.IndexOf("=") + 1), _
                    System.Globalization.NumberStyles.AllowDecimalPoint, _
                    culture, mm.Right)
            End If
            If s.StartsWith("Top=") Then
                Single.TryParse(s.Substring(s.IndexOf("=") + 1), _
                    System.Globalization.NumberStyles.AllowDecimalPoint, _
                    culture, mm.Top)
            End If
            If s.StartsWith("Bottom=") Then
                Single.TryParse(s.Substring(s.IndexOf("=") + 1), _
                    System.Globalization.NumberStyles.AllowDecimalPoint, _
                    culture, mm.Bottom)
            End If
        Next
        Return mm
    End Function
End Class


' ##############################################################################
' ############################# MyPageSettings.vb ##############################
' ##############################################################################
Public Class MyPageSettings
    Inherits Printing.PageSettings

    Private _Margins As New MyMargins

    Public Sub New()
        MyBase.New()
    End Sub

    Public Sub New(ByVal ps As Printing.PrinterSettings)
        MyBase.New(ps)
        _Margins = New MyMargins(MyBase.Margins)
    End Sub

    Public Overloads Property Margins() As MyMargins
        Get
            Return _Margins
        End Get
        Set(ByVal value As MyMargins)
            _Margins = value
        End Set
    End Property
End Class

' ##############################################################################
' ########################### MyPageSetupDialog.vb #############################
' ##############################################################################
Public Class MyPageSetupDialog

    Private _PrinterSettings As Printing.PrinterSettings
    Private _PageSettings As MyPageSettings
    Private _EnableMetric As Boolean

    Public Sub New()
        MyBase.New()
        InitializeComponent()
    End Sub

    Public Function ShowDialog() As DialogResult
        Dim frmDlg As New dlgMyPageSetupDialog
        If _PageSettings Is Nothing Then
            _PageSettings = New MyPageSettings(GetDefaultPrinterSettings())
        End If
        frmDlg.PageSettings = DirectCast(_PageSettings.Clone, MyPageSettings)
        If _PrinterSettings IsNot Nothing Then
            frmDlg.PrinterSettings = DirectCast(_PrinterSettings.Clone,  _
                Printing.PrinterSettings)
        End If
        frmDlg.EnableMetric = _EnableMetric
        Dim dlgresult As DialogResult = frmDlg.ShowDialog()
        If dlgresult = DialogResult.OK Then
            _PageSettings = DirectCast(frmDlg.PageSettings.Clone,  _
                MyPageSettings)
            _PrinterSettings = _PageSettings.PrinterSettings
        End If
        Return dlgresult
    End Function

    Private Function GetDefaultPrinterSettings() As Printing.PrinterSettings
        Dim prs As New Printing.PrinterSettings
        For Each prtn As String In Printing.PrinterSettings.InstalledPrinters
            prs.PrinterName = prtn
            If prs.IsDefaultPrinter Then
                Return prs
            End If
        Next
        Return Nothing
    End Function

    Public Property PageSettings() As MyPageSettings
        Get
            Return _PageSettings
        End Get
        Set(ByVal value As MyPageSettings)
            _PageSettings = value
        End Set
    End Property

    Public Property PrinterSettings() As Printing.PrinterSettings
        Get
            Return _PrinterSettings
        End Get
        Set(ByVal value As Printing.PrinterSettings)
            _PrinterSettings = value
        End Set
    End Property

    Public Property EnableMetric() As Boolean
        Get
            Return _enableMetric
        End Get
        Set(ByVal value As Boolean)
            _enableMetric = value
        End Set
    End Property
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.