حل استخدام التقارير في WPF

حينما تستخدم التقارير في تطبيقات Windows Forms أو في ASP.NET، يكون الأمر سهلا، ولكن حينما تستخدمها في WPF ، ستواجهك بعض العقبات، ساستعرض هنا الطريقة المثلى والمشاكل التي قد تواجهك في أثناء العمل

بداية لا توجد أداة مدمجة في WPF تسمح لك باستخدام التقارير مباشرة ( أقصد بالتقارير بالدرجة الأولى تقارير الفيجوال ستوديو نفسه، وقد ينطبق هذا الشرح على تقارير الكريستال ريبورت )، وإذا أردت استخدام التقارير في  WPF  فعليك باستدعاء عارض التقارير الموجود في Windows Forms.

 

طريقة الاستدعاء سهلة، عليك باتباع الخطوات التالية

– أضف المرجع Add Reference التالي إلى المشروع / Microsoft.Reporting.WinForms

– قم باستدعاء المرجع في منطقة الاستدعاء : xmlns:rv="clr-namespace:Microsoft.Reporting.WinForms;assembly=Microsoft.ReportViewer.WinForms"  من داخل الصفحة

– قم بوضع الوسم WindowsFormsHost أينما تحب في المشروع وهذه الأداة مسؤولة عن جلب أدوات من الWindows Forms  بداخل WPF

– استدعي أداة عارض التقارير بداخل الوسم بالأعلى كالتالي <rv:ReportViewer

تصبح المحصلة لديك كالصورة التالية :

wpf report

 

الآن نأتي لتحميل ملف التقرير ، مع العلم أنني سأفترض أنك قد أعددت تقريرا

           Private Sub Button_Click(sender As Object, e As RoutedEventArgs) 
'' جلب الداتا سيت التي قد قمت بربطها بالتقرير، مهما كان اسمها
Dim dataset As New JewellyManagement.KhalilSaleemDataset
dataset.BeginInit()


'' تعبئة البيانات بالشكل المطلوب وتستطيع كتابة أي شروط او استعلامات كما تشاء ، الأمر روتيني لمن استخدم التقارير سابقا
Dim conn As New SqlCeConnection(My.Settings.JDConnectionString)
Dim cmd As SqlCeCommand = conn.CreateCommand()
cmd.CommandText = "SELECT [ID], [DOB], [Name], [Price], [Notes], CASE [Ttype] WHEN 1 THEN 'يومي' WHEN 2 THEN 'شهري' WHEN 3 THEN 'سنوي' ELSE 'يومي' End as TType,Currency FROM [WalletOut]"
Dim da As New SqlCeDataAdapter(cmd)
da.Fill(dataset.CInfo)



Dim reportinfo As New Microsoft.Reporting.WinForms.ReportDataSource()
reportinfo.Name = "DSInfo"
reportinfo.Value = dataset.CInfo
Me._reportViewer.LocalReport.DisplayName = ReportNameWithDate("تقرير المصروفات ")
Me._reportViewer.LocalReport.DataSources.Add(reportinfo)
Me._reportViewer.LocalReport.ReportEmbeddedResource = "JewellyManagement.WalletFullReport.rdlc"
dataset.EndInit()
_reportViewer.RefreshReport()
End Sub

wpf report

في مثالي انا استخدمت قاعدة بيانات داخلية وربطت البيانات بها، أنت حر كما تريد، قمت بتوزيع الكود إلى 3 أقسام ، لتفهم أن القسم الأول عليك باستدعاء datasource

في القسم الثاني عليك بكتابة استعلامك وملء البيانات وهو إجراء روتيني لك كمبرمج.

 في القسم الثالث عليك بارسال اسم مصدر البيانات من التقرير وفي حالتي كان DSInfo وكذلك عليك استدعاء اسم التقرير ومساره في JewellyManagement.WalletFullReport.rdlc ، وهنا تكمن الخدعة، وهنا سبب كتابتي للمقال.

 

توضيح حول المسار

المعتاد دائما في هذا الكود هو استدعاء المسار بالشكل التالي

          _reportViewer.LocalReport.ReportPath = "../../Incomes/BrakeReport.rdlc" 

حيث ../../ تشير إلى اسم المجمع assembly وثم اسم فضاء الأسماء namespace و Incomes على سبيل المثال هي للمجلد الفرعي ( الداخلي ) الذي أضع فيه التقرير والذي يحمل اسم BrakeReport.rdlc

هذا الأمر طبيعي في Windows Forms ونفس الشيء في WPF المشكلة تظهر حينما تحاول نشر البرنامج ستجد أن المشاكل تظهر ولا ينم عرض التقرير

السبب بسيط هو أن التقرير Embeded Resource وبالتالي لا مسار فيزيائي له، وستفشل كل الطرق في WPF لجلب المسار

الحل يكمن في اسدعاء خاصية ReportEmbeddedResource بدلا من ReportPath  كما عملت في الكود بالأعلى ، ولكن هنالك خدعة بسيطة يجب عملها ألا وهو استبدال ../../ بالمسار الحقيقي في Embedding

في السي شارب عليك باستدعاء اسم المجمع ثم نقطة ، ثم تضع اسم فضاء الأسماء ثم نقطة أي أنه يصبح كالتالي

        _reportViewer.LocalReport.ReportEmbeddedResource = "AssemblyName.NameSpace.ReportName.rdlc"

وطبيعي لو كنت قد وضعت التقرير في مجلد فرعي أن تضيف اسم المجلد الفرعي كفضاء أسماء لأن السي شارب  تعامل المجلدات كفضاءات أسماء فيصبح الأمر هكذا

        _reportViewer.LocalReport.ReportEmbeddedResource = "AssemblyName.NameSpace.FolderName.ReportName.rdlc"

أما في الفيجوال بيسك دوت نت الأمر يختلف فلا يوجد لديك فضاءات اسماء فرعية ( وهذه المعلومة تكلف ثمنها لأني سهيت عنها فاسغرقتني 3 أيام من البحث لحين خطرت على بالي وحللت المشكلة وقررت أن أكتب المقال حتى لا يقع غيري بها ) ، فكل ما عليك فعله هو كتابة اسم المجمع ثم اسم التقرير مهما كان في مجلدات فرعية كالتالي

        _reportViewer.LocalReport.ReportEmbeddedResource = "AssemblyName.ReportName.rdlc

والدليل على كلامي انك حاول وضع تقرير ثان في مشروع الفيجوال بيسك بنفس الاسم وستجد ان البرنامج يرفض هذا ، أقصد نفس الاسم البرمجي، لأنه سيكون في المجمع مباشرة بدون فضاء أسماء، نعم ويمكنك إنشاء فضاءات الأسماء الخاصة بك كما تريد.

بالتوفيق للجميع

About the author

خليل سليم

Leave a Comment

هذا الموقع يستخدم Akismet للحدّ من التعليقات المزعجة والغير مرغوبة. تعرّف على كيفية معالجة بيانات تعليقك.