المتابعون للمدونة

السبت، 9 نوفمبر 2013

طباعة التقرير مباشرة


س: كيف يمكن طباعة تقرير مباشرة بدون عرضه أولا في الأداة ReportViewer؟ 

ج: يمكن فعل هذا بكتابة فئة خاصة تقوم بهذا الأمر.. وقد بحثت على الإنترنت ووجدت بالفعل هذه الفئة مكتوبة واسمها AutoPrintCls، لكن كان بها عيب أنها لا تطبع الورقة العرضية Landscape بشكل صحيح، فقمت ببعض التصحيحات فيها، وهي تعمل الآن بشكل صحيح.. كما أنني وضعت هذه الفئة داخل فئة أخرى اسمها ReportPrinter لإخفاء تفاصيلها، بحيث يمكن تنفيذ أمر الطباعة مباشرة بسطر واحد باستدعاء الوسيلة المشتركة ReportPrinter.Print.
ملحوظة:
لكي يعمل هذا الكود يجب أن تضيف إلى المشروع مرجعا Reference إلى النطاقين التاليين:
Microsoft.ReportViewer.Common
Microsoft.ReportViewer.WinForms
لفعل هذا اضغط القائمة الرئيسية Project ومنها اضغط الأمر Add References.. وفي النافذة التي ستظهر، اختر من القائمة اليسرى العنصر Extensions.. لاحظ أنك ستجد إصدارين من الملف Microsoft.ReportViewer.WinForms. اختر الإصدار الأحدث (رقم 11) كما تظهر تفاصيله في الجزء الأيمن من النافذة عند اختيار العنصر.
هذا هو الكود:


Imports Microsoft.VisualBasic

Imports System

Imports System.IO

Imports System.Text

Imports System.Globalization

Imports System.Drawing

Imports System.Drawing.Imaging

Imports System.Drawing.Printing

Imports Microsoft.Reporting.WinForms

Imports System.Collections.Generic

Imports System.Collections.Specialized

Imports System.Diagnostics

Imports System.ComponentModel

Imports System.Data

Imports System.Linq

Imports System.Threading.Tasks

Imports System.Windows.Forms

 

Public Class ReportPrinter

    Public Shared Sub Print(Report As LocalReport)

        Dim AuroPrint As New AutoPrintCls(Report)

        AuroPrint.Print()

    End Sub

 

    Public Shared Sub Print(Report As ServerReport)

        Dim AuroPrint As New AutoPrintCls(Report)

        AuroPrint.Print()

    End Sub

 

    Private Class AutoPrintCls

        Inherits PrintDocument

 

        Private m_pageSettings As PageSettings

        Private m_currentPage As Integer

        Private m_pages As New List(Of Stream)()

 

        Friend Sub New(ByVal serverReport As ServerReport)

            Me.New(CType(serverReport, Report))

            RenderAllServerReportPages(serverReport)

        End Sub

 

        Friend Sub New(ByVal localReport As LocalReport)

            Me.New(CType(localReport, Report))

            RenderAllLocalReportPages(localReport)

        End Sub

 

        Private Sub New(ByVal report As Report)

            Dim reportPageSettings As ReportPageSettings = report.GetDefaultPageSettings()

            m_pageSettings = New PageSettings()

            m_pageSettings.PaperSize = reportPageSettings.PaperSize

            m_pageSettings.Margins = reportPageSettings.Margins

            m_pageSettings.Landscape = reportPageSettings.IsLandscape

        End Sub

 

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)

            MyBase.Dispose(disposing)

 

            If disposing Then

                For Each s As Stream In m_pages

                    s.Dispose()

                Next s

 

                m_pages.Clear()

            End If

        End Sub

 

        Protected Overrides Sub OnBeginPrint(ByVal e As PrintEventArgs)

            MyBase.OnBeginPrint(e)

 

            m_currentPage = 0

        End Sub

 

        Protected Overrides Sub OnPrintPage(ByVal e As PrintPageEventArgs)

            MyBase.OnPrintPage(e)

 

            Dim pageToPrint As Stream = m_pages(m_currentPage)

            pageToPrint.Position = 0

 

            ' Load each page into a Metafile to draw it.

            Using pageMetaFile As New Metafile(pageToPrint)

                Dim adjustedRect As New Rectangle(e.PageBounds.Left - CInt(Fix(e.PageSettings.HardMarginX)), e.PageBounds.Top - CInt(Fix(e.PageSettings.HardMarginY)), e.PageBounds.Width, e.PageBounds.Height)

                ' Draw a white background for the report

                e.Graphics.FillRectangle(Brushes.White, adjustedRect)

 

                ' Draw the report content

                e.Graphics.DrawImage(pageMetaFile, adjustedRect)

 

                ' Prepare for next page.  Make sure we haven't hit the end.

                m_currentPage += 1

                e.HasMorePages = m_currentPage < m_pages.Count

            End Using

        End Sub

 

        Protected Overrides Sub OnQueryPageSettings(ByVal e As QueryPageSettingsEventArgs)

            e.PageSettings = CType(m_pageSettings.Clone(), PageSettings)

        End Sub

 

        Private Sub RenderAllServerReportPages(ByVal serverReport As ServerReport)

            Try

                Dim deviceInfo As String = CreateEMFDeviceInfo(0, 0)

 

                ' Generating Image renderer pages one at a time can be expensive.  In order

                ' to generate page 2, the server would need to recalculate page 1 and throw it

                ' away.  Using PersistStreams causes the server to generate all the pages in

                ' the background but return as soon as page 1 is complete.

                Dim firstPageParameters As New NameValueCollection()

                firstPageParameters.Add("rs:PersistStreams", "True")

 

                ' GetNextStream returns the next page in the sequence from the background process

                ' started by PersistStreams.

                Dim nonFirstPageParameters As New NameValueCollection()

                nonFirstPageParameters.Add("rs:GetNextStream", "True")

 

                Dim mimeType As String

                Dim fileExtension As String

 

 

                Dim pageStream As Stream = serverReport.Render("IMAGE", deviceInfo, firstPageParameters, mimeType, fileExtension)

 

 

 

                ' The server returns an empty stream when moving beyond the last page.

                Do While pageStream.Length > 0

                    m_pages.Add(pageStream)

 

                    pageStream = serverReport.Render("IMAGE", deviceInfo, nonFirstPageParameters, mimeType, fileExtension)

                Loop

            Catch e As Exception

                MessageBox.Show("possible missing information ::  " & e.Message)

            End Try

        End Sub

 

        Private Sub RenderAllLocalReportPages(ByVal localReport As LocalReport)

            Try

                Dim deviceInfo As String = CreateEMFDeviceInfo(0, 0)

 

                Dim warnings() As Warning

 

                localReport.Render("IMAGE", deviceInfo, AddressOf LocalReportCreateStreamCallback, warnings)

            Catch e As Exception

                MessageBox.Show("error :: " & e.Message)

            End Try

        End Sub

 

        Private Function LocalReportCreateStreamCallback(ByVal name As String, ByVal extension As String, ByVal encoding As Encoding, ByVal mimeType As String, ByVal willSeek As Boolean) As Stream

            Dim stream As New MemoryStream()

            m_pages.Add(stream)

 

            Return stream

        End Function

 

        Private Function CreateEMFDeviceInfo(startPage As Integer, endPage As Integer) As String

            Dim hundrethsOfInch As Integer = If(m_pageSettings.Landscape, m_pageSettings.PaperSize.Height, m_pageSettings.PaperSize.Width)

            Dim hundrethsOfInch2 As Integer = If(m_pageSettings.Landscape, m_pageSettings.PaperSize.Width, m_pageSettings.PaperSize.Height)

            Dim _text As String = String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}{4}{5}", New Object() {ToInches(m_pageSettings.Margins.Top), ToInches(m_pageSettings.Margins.Left), ToInches(m_pageSettings.Margins.Right), ToInches(m_pageSettings.Margins.Bottom), ToInches(hundrethsOfInch2), ToInches(hundrethsOfInch)})

            Return String.Format(CultureInfo.InvariantCulture, "emf{0}{1}{2}", New Object() {startPage, endPage, _text})

        End Function

 

        Private Shared Function ToInches(ByVal hundrethsOfInch As Integer) As String

            Dim inches As Double = hundrethsOfInch / 100.0

            Return inches.ToString(CultureInfo.InvariantCulture) & "in"

        End Function

    End Class

End Class

وسأشرح لكم كيفية استخدام هذه الفئة في الموضوع التالي.

 

 

هناك 3 تعليقات:

  1. جزاك الله كل خير أستاذ حمدي على هذه المعلومات , لدي سؤال اذا تكرمت , كيف يمكنني ان اركب سلسلة نصية من عدة حروف بحيث يكون كل حرف منها بلون مختلف عن الأخر عند عرض النص في textbox, وكيف يمكن تغير لون حرف معين في سلسلة نصية دون الحروف الأخرى

    ردحذف
  2. الكود يعمل عند تشغيل المشروع في بيئة الفيجوال ولكن عند تشغيل البرنامج خارج بيئة الفيجوال لا يعمل وتظهر رسالتين الأولى "error : An error occurred during local report processing" والرسالة الثانية "الفهرس خارج النظاق. يجب ألا يكون قيمته سالبة ويجب ألا يكون أقل من حجم المجموعة اسم المعلمة: index" علماً بأن الفيجوال يعطيني ثلاث رسائل تحذيرية بسبب الممغيرات الفارغة وهي mimeType , fileExtension , warnings

    ردحذف
    الردود
    1. أخي جزيت خيراً على الموضوع ولكن لم أجد الإصدار 11 من Microsoft.ReportViewer.WinForms علماً بأن الدوت نت فريم وورك عندي هو .NET Framework 4 أرجو المساعدة

      حذف

ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.

صفحة الشاعر