صدرت
VS.NET 2019 أول أمس، ولا أرى فيها أي جديد، لأن فيجوال بيزيك 16 و سي شارب 8
و دوت نت كور 3 كلها لم تصدر بعد وأمامها شهران أو ثلاثة!
بل
والمستفز أكثر أن VS.NET
2019 نزلت بإصدار دوت نت كور 2.1 وليس 2.2، وعلى من يريد هذا الإصدار الأخير
فعليه تنزيله وإعداده في خطوة مستقلة!
لكل
هذا قررت أن أصنع نسخة من Vazor تعمل بالإصدار 2.2 من نواة دوت نت، حتى يمكنكم تجربتها في دوت نت
2017.. تجدونها هنا:
يمكنكم
تنزيل هذا المشروع إلى أجهزتكم بضغط الزر المنسدل Clone or download ،
واختيار Download
Zip.
وكما
ذكرت، فإن هذه النسخة تحتاج إلى دوت نت كور 2.2.. إذا لم يكن لديكم، فيمكنكم
تنزيله من هذه الصفحة:
مع
ضرورة اختيار رابط التنزيل من العمود الأوسط لأنه يحتوي على النسخ الخاصة
بالمبرمجين وليس المستخدمين، مع التأكد من اختيار نسخة Windows Installer x84 للأجهزة التي عليها ويندوز 32 بت، ونسخة Windows Installer x64 لنسخ ويندوز 64 بت.
وبعد
تنزيل هذه النسخة برنامج الإعداد، قم بتشغيله وواصل خطوات الإعداد معه.
والآن
فكوا ضغط ملف المشروع، واضغطوا الملف Vazor.sln لفتح المشروع في
فيجوال ستديو.. هذا المشروع يحتوي على ثلاثة مشاريع فرعية وهي:
1-
Vazor:
هذا
المشروع مكتبة كود ينتج عنه الملف Vazor.dll في المجلد debug/bin.. هذا الملف هو الذي تستخدمه في مشاريعك (بإضافة مرجع Reference إليه) لجعل
Razor يعرض صفحات العرض التي تكتبها بكود vbxml بدلا
من cshtml.. لاحظ أن المشروعين الآخرين يضيفان مرجعا للمشروع Vazor نفسه
لهذا يستطيعان استخدام الفئات الموجودة فيه.
وقد
بسطت المشروع Vazor
جدا ليكون استخدامه سهلا، كما سترون في الشرح التالي.
مستقبلا،
سأوفر Vazor.dll كحزمة إضافية Nuget بإذن الله، حتى يمكن استخدامه في مشاريعكم بخطوة واحدة، لكن
المشكلة الآن أننا لا نملك قالبا لمشاريع ASP.NET بلغة فيجوال
بيزيك.. أنشأت أحد هذه القوالب على جهازي (وهو أمر ليس معقدا)، لكني ما زلت أطور
في المشروع وسيكون كل شيء عرضة للتغير، لهذا من الأفضل أن يكون إنشاء القالب آخر
خطوة.
لهذا
يجب عليكم استخدام مشروعي فيجوال بيزيك المرفقين كقالب.
2-
WepApp1:
هذا
مشروع ASP.NET Core
MVC مكتوب بلغة فيجوال بيزيك دوت نت.
3-
VazorPages1:
هذا
مشروع ASP.NET Core
Razor Pages مكتوب بلغة فيجوال بيزيك دوت نت.
لاحظ
أن كلا من المشروعين الأخيرين يحتوي على بعض صفحات العرض بصيغة cshtml وبعضها
الآخر بصيغة vbxml كمثال على تعايش النوعين معا.. وكلاهما مجرد مثال بدائي يمكنك تعديله والبناء عليه
لإنشاء مشروع خاص بك.
كيف
يمكنك إنشاء صفحة عرض من النوع vbxml؟
الأمر
بسيط للغاية.. اتبع هذه الخطوات في مشروع من النوع MVC:
1-
حدد المجلد Views وأضف إليه مجلدا جديدا اسمه Book.. حدد
هذا المجلد وأضف إليه فئة جديدة New
Class اسمها Book.vazor.vb.. لاحظ
أن وجود .vazor في الاسم مجرد
عملية تنظيمية، ليسهل عليك معرفة محتوى كل ملف من اسمه.
2-
في ملف الكود، غير اسم الفئة الجديدة من Book إلى BookView ليكون
أكثر وضوحا ومنعا للالتباس مع أي فئة اسمها Book في
قالب البيانات Model.. واجعل هذه الفئة ترث الفئة VazorView:
Imports Vazor
Public Class BookView
Inherits VazorView
End Class
بمجرد
أن تضغط Enter بعد الاسم كتابة Inherits
VazorView سيضيف محرر الكود تعريفا للخاصية Content داخل
الفئة، لأني عرفت هذه الخاصية على أنها واجبة الاستبدال MustOverride في
الفئة الأم.. في هذه الخاصية اكتب الكود الذي يعيد محتوى صفحة العرض في صورة
مصفوفة من الوحدات الثنائية Byte
Array، لإرساله إلى Razor كأنه محتويات الصفحة التي عليه عرضها في المتصفح.. اجعل كود هذه
الخاصية كالتالي:
Public Overrides ReadOnly Property Content() As Byte()
Get
Dim html = GetVbXml(Me).ParseTemplate(Books)
Return Encoding.GetBytes(html)
End Get
End Property
في
الغالب هذا هو الكود الذي ستكتبه في هذه الخاصية في كل صفحات Vazor التي
ستنشئها. (تعديل: لهذا السبب نقلت كود هذه الخاصية إلى الفئة VazorView ولم تعد بحاجة إلى كتابتها بنفسك.. لكن لو احتجت إلى كتابة المزيد من الكود فيها لأي سبب، فيمكنك أن تضيفها مرة أخرى لاستبدال الخاصية الاصلية، حيث يمكنك أن تعدل فيها كما تشاء.
لاحظ
أن:
-
الوسيلة GetVbXml هي وسيلة سنقوم بتعريفها بأنفسنا بعد قليل، لنضع فيها كود vbxml الخاص
بالصفحة.. وهي تعيد كائنا من النوع XElement يحمل كود XML.
-
ParseTemplate هي وسيلة إضافية للفئة XElement عرفتها في المشروع
Vazor.. ومهمتها معالجة قالب البيانات ForEach = "m" كما شرحت في الموضوع السابق، وهي تعيد نصا يحمل كود HTML.
-
Encoding هي خاصية معرفة في الفئة الأم VazorView،
وقيمتها الافتراضية هي System.Text.Encoding.UTF8 لاستخدام الترميز UTF8 في تحويل النص إلى مصفوفة ثنائية.. يمكنك استخدام أي ترميز آخر لو
أردت، بإرساله إلى حدث إنشاء هذه الفئة كما سأوضح بعد قليل.
-
Books هي خاصية تقوم أنت بتعريفها لتحتوي على مجموعة من الكتب التي تريد
عرضها في الصفحة.. مثلا:
Public ReadOnly Property Books As List(Of Book)
حيث
Book هو اسم فئة في قالب البيانات Mode تحمل
بيانات الكتاب.. لهذا قلت لك يجب أن نسمي فئة العرض BookView.
-
ولو كنت تحتاج إلى التعامل مع كائن بيانات العرض ViewData في
كتابة كود الصفحة، فأنشئ خاصية لوضعه فيها:
Public ReadOnly Property ViewData() As ViewDataDictionary
- والآن يجب أن
نكتب حدث الإنشاء New لنستقبل عبره مجموعة الكتب المراد عرضها، وكائن بيانات العرض، ولو
أردت استقبال أي شيء آخر فلك مطلق الحرية في تعريف المزيد من المعاملات لهذا
الحدث:
Public Sub New(books As List(Of Book), viewData As ViewDataDictionary)
MyBase.New("Book", "Views\Book", "قائمة الكتب")
Me.Books = books
Me.ViewData = viewData
viewData("Title") = Title
End Sub
لاحظ
أن أول سطر في حدث الإنشاء يجب أن يستدعي منشئ الفئة الأم MyBase.New ،
ويرسل إليه البيانات التعريفية للصفحة وهي:
1-
اسم الصفحة (بدون امتداد)، وهو هنا "Book".. ستوضع هذه
القيمة في الخاصية Name في الفئة الأم.
2-
مسار المجلد الذي فيه الصفحة، وهو هنا "Views\Book".. ستوضع هذه القيمة في الخاصية Path في
الفئة الأم.
3-
العنوان الذي ستعرضه الصفحة في الشريط العلوي للمتصفح، وهو هنا "قائمة الكتب".. ستوضع هذه القيمة في الخاصية Title في
الفئة الأم.
4- وهناك صيغة ثانية لحدث الإنشاء تستقبل معاملا رابعا يمثل
الترميز الذي تريد استخدامه لعرض الصفحة.. ستوضع هذه القيمة في الخاصية Encoding في الفئة الأم.. مثال:
MyBase.New("Book", "Views\Book", "قائمة الكتب",
System.Text.Encoding.UTF7)
وهذا
هو كل شيء.. هكذا ستبدو الفئة كاملة:
Imports Microsoft.AspNetCore.Mvc.ViewFeaturesImports Vazor
Public Class BookView
Inherits VazorView
Public ReadOnly Property Books As List(Of Book)
Public ReadOnly Property ViewData() As ViewDataDictionary
Public Sub New(books As List(Of Book), viewData As ViewDataDictionary)
MyBase.New("Book", "Views\Book", "قائمة الكتب")
Me.Books = books
Me.ViewData
= viewData
viewData("Title") = Title
End Sub
Public Overrides ReadOnly Property Content() As Byte()
Get
Dim html = GetVbXml(Me).ParseTemplate(Books)
Return Encoding.GetBytes(html)
End Get
End Property
End Class
ملحوظة:
لو أنشأت قالبا للمشروع بإذن الله، فسأجعل كل هذه الخطوات تتم آليا، بمجرد أن
تختار إضافة عنصر من النوع Vazor
View من مربع حوار إضافة عنصر!
والآن
لم يبق إلا الخطوة الأخيرة والأهم، وهي إنشاء الدالة GetVbXml التي سنصمم فيها الصفحة.
ولتنظيم
الأمور بشكل مريح، سنضيف هذه الدالة في ملف مستقل، في تعريف جزئي Partial للفئة BookView.. وسنجعل اسم هذا الملف في متصفح المشاريع Book.vbxml.vb، ونكتب
فيه ما يلي:
Protected Shared Function GetVbXml(view As BookView) As XElement
Return _
<vbxml>
<h3>Book names:</h3>
<ul>
<%= (Iterator Function()
For Each bk In view.books
Yield <li><%= bk.Name %></li>
Next
End Function)() %>
</ul>
<p>More details:</p>
<ul>
<li ForEach="bk">
Id: <bk.Id/><br/>
Name: <bk.Name/><br/>
<p>Author: <bk.Author/></p>
</li>
</ul>
<script>
var x = 5;
document.writeln(
"Books
count = <%= view.Books.Count() %>");
</script>
</vbxml>
End Function
End Class
هذه
الصفحة ستعرض أسماء الكتب وتفاصيلها، وهي تتكون من كود HTML5 عادي،
تم تضمين بعض كود فيجوال بيزيك فيه بين العلامتين <%=
%>; المستخدمة في صفحات ASP القديمة بدلا من
استخدام العلامة @ كما في Razor.
وهكذا
نكون قد انتهينا من تصميم الصفحة.. بقي شيء واحد فقط، هو أن نعرضها.
الطبيعي
أن يكون هناك متحكم Controller في مشروع MVC مسئول عن عرض الصفحة.. سنفترض أن لدينا متحكم اسمه Details
وبداخله وسيلة أداء Action
Method اسمها Book يتم استدعاؤها حينما يطلب المستخدم عرض صفحة الكتب.. سنكتب في هذه
الوسيلة الكود التالي:
Public Function Index() As IActionResult
Dim
Books = GetBooksFromDB()
Dim bv = New BookView(Books, ViewData)
Dim viewName =
Vazor.VazorViewMapper.Add(bv)
Return View(viewName)
End Function
في
البداية حصلنا على الكتب من قاعد البيانات ووضعناها في المتغير Book..
لمحاكاة هذا يمكنك أن تعرف قائمة فيها بعض الكتب وتجعل الوسيلة GetBooksFromDB تعيدها على أنها نتيجة البحث.
بعد
هذا سنرسل قائمة الكتب إلى حدث إنشاء الفئة BookView هي
وبيانات العرض ViewData.
الآن
نحتاج إلى تسجيل هذه النسخة من الفئة BookView في خريطة الصفحات
باستخدام الوسيلة VazorViewMapper.Add .. ستأخذ الصفحة اسما متفردا في الخريطة، وستعيده إلينا هذه
الوسيلة.. الآن كل ما سنفعله هو أن نرسل اسم هذه الصفحة الذي حصلنا عليه إلى
الوسيلة View الخاصة بالمتصفح ونطلب منها عرضها.. بهذا سيذهب Razor إلى
مزود الملفات التخيلي Virtual File Provider الخاص بـ Vazor ليطلب محتويات هذه الصفحة، وسيبحث عنها المزود في الخريطة فيجدها،
فيستدعي الخاصية Content التي كتبناها في الفئة BookView للحصول على محتوى
الصفحة، وتسليمها إلى Razor الذي سيعرضها في المتصفح بنجاح!
لاحظ
أنك لا تحتاج إلى تغيير صفحات العرض المشتركة SharedView (مثل
صفحة إطار العرض Layout)، فهي لا تحتوي على كود سي شارب.. يمكنك أن تتركها بصيغة cshtml وستعمل
بشكل صحيح.. لكن لو أردت إنشائها بضيغة vbxml فعليك تسجيلها في
الخريطة في الوسيلة Startup.Configure باستدعاء الوسيلة AddStatic، لأن هذه الصفحات تترجم مرة واحدة فقط ويظل محتواها ثابتا عند
عرضها مع كل صفحات الموقع:
Vazor.VazorViewMapper.AddStatic(New
LayoutView())
وهذا
هو كل شيء!
هذه
هي ببساطة طريقة استخدام Vazor وكود vbxml.
ويمكنك
تطبيق نفس الخطوات في مشاريع Razor
Pages لكن مع مراعاة الاختلافات التي شرحتها في الموضوع السابق.
واضح
أن الأمر في منتهى البساطة، لكن هناك عيب أساسي فيه، هو أن محرر الكود في ففيجوال
بيزيك لا يساعدك في إكمال أسماء التيجان والسمات الخاصة ب HTML5 ولا
كود جافا سكربت وأنت تكتبها في كود vbxml، وهذا سيجعل الأمر
صعبا، أو ستصطر إلى كتابة هذه الأكواد في محرر HTML5 أولا
(أي صفحة htm تفتحها في فيجوال ستديو) ثم تنقلها إلى صفحة vbxml لتضبط
كود فيجوال بيزيك المضمن فيها، وهي طريقة متعبة بعض الشيء!
سأحل
هذه المشكلة بإذن الله وسأجعل محرر الكود يراعي هذا، لكنه أمر ليس سهلا يحتاج
لكتابة مكون إضافي لفيجوال ستديو وما زلت أقرأ فيه (لحل عملي سريع لهذه المشكلة، اقرأ هذا المنشور).. سيكون الأمر أسهل وأسرع طبعا
لو وجدت متحمسين يساعدون في إكمال المشروع، فحتى الآن ما زلت أعمل بمفردي.. أرجو
أن تدخلوا على المشروع في GitHub وتحاولوا المشاركة.
ليست هناك تعليقات:
إرسال تعليق
ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.