الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

توسيع مجال الأسماء My باستخدام My Extensibility

بدأه محمد سامر أبو سلو في 16 أبريل 2008 · 1 رد · 1,189 مشاهدة · في Microsoft Visual Basic.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

تم تقديم مجال الأسماء My بدءا من Visual Basic 2005 ليوفر اختصارات للطرائق واستدعاءات API الشائعة ومنذ ذلك الوقت كان يمكن للمستخدمين كتابة توسعاتهم الخاصة لمجال الأسماء My مضيفين له مكتبات الكود الخاصة بهم. وقد قدم My Extensiility كجديد في Visual Basic 2008 مما سهل توسيع المجال My. ومع ميزة My Extensibility الجديدة أصبح بالإمكان تفعيل وإلغاء تفعيل My Extensibility من خلال مصمم المشاريع أو عندما يتم ربط أو إزالة مرجع لمجمع في المشروع الأمر الذي جعل عملية توسيع بيئة تطوير Visual studio أكثر بساطة.

طرق توسيع المجال My

هناك القليل من نماذج الكود التي يمكن استخدامها لتوسيع المجال My. والطريقة الأسهل لعمل ذلك هي تلك التي نعرفها سابقا فعملية إضافة أي شئ للمجال My هي عملية مماثلة لعملية إضافة أي شئ لأي مجال أسماء آخر كما في المثال

Namespace My.HandyStuffForMy
	<Global.Microsoft.VisualBasic.HideModuleName()> _
	Friend Module HandyStuffForMyModule
		Sub Foo()
			...
		End Sub

		Property Bar()
			...
		End Property
	End Module
End Namespace

الذي يجعل الإجراء Foo و الخاصية Bar يظهران ضمن المجال HandyStuffForMy ضمن المجال My. حيث استخدمنا الواصفة attribute المسماة HideModuleName التي تمنع اسم الـ module من الظهور لأنك لا تحتاجه للوصول إلى العناصر المحتواة ضمنه. وإن أردت إضافة هذه العناصر للمجال My بدون إنشاء مجال فرعي عدل اسم المجال في الكود السابق ليصبح My فقط كما يلي

Namespace My
	<Global.Microsoft.VisualBasic.HideModuleName()> _
	Friend Module HandyStuffForMyModule
		Sub Foo()
			...
		End Sub

		Property Bar()
			...
		End Property
	End Module
End Namespace

وإن استخدمت اسم مجال موجود سلفا ضمن المجال My كـ Resources مثلا فهذه العناصر سيتم إضافتها لذلك المجال مما يعطيك مرونة كبيرة في كيفية الوصول إلى توسعاتك. والشئ الذي يجب الانتباه إليه هو محدد الوصول فمحدد الوصول Friend سيقوم بمنع المجمعات الأخرى من الوصول إلى هذه العناصر وإن استخدمت محدد الوصول Public ربما تتضارب هذه العناصر مع رموز معرفة في المشاريع الأخرى التي تستخدم المجال My

التوسيع باستخدام الورقة المفردة Singleton

My.Computer و My.Settings و My.Application هي تواجدات وحيدة الورقة Singleton Instances للفئات My.MyComputer و My.MySettings و My.MyApplication حيث يمكننا إضافة عناصر لهذه الفئات بسهولة باستخدام ميزة الفئات المجزأة Partial Class فمثلا الكود التالي يضيف إجراء يدعى Shutdown للغرض My.Computer

Namespace My
	Partial Class MyComputer
		Sub Shutdown()
			...
		End Sub
	End Class
End Namespace

كما يمكن استخدام هذا الكود لتوسيع My.Application و My.Settings أيضا حيث تمكنك ميزة الفئات المجزأة من إضافة عناصر إلى فئات معرفة في مكان آخر وهذا يتضمن فئات مثل MyComputer في مشاريع Visual Basic حيث يقوم المترجم بحقن الفئات قبل أن يتم ترجمة الكود.

وإذا أردت جعل عناصرك التي قمت بإضافتها يمكن الوصول إليها كورقة مفردة مثل الفئات المذكورة يجب عليك إضافة خاصية للقراءة فقط للمجال My تعيد تواجدا عاما يماثل ذلك المزود من ThreadSafeObjectProvider(Of T) الذي يقوم بإنشاء صورة من تلك الفئة على مستوى المسلك Thread والكود التالي يرينا كيفية إضافة My.CustomMyObject مع عناصره

Namespace My
  <Global.System.ComponentModel.EditorBrowsable _
  (Global.System.ComponentModel.EditorBrowsableState.Never)> _
  Partial Friend Class MyCustomMyObject
	Public Sub Foo()
			...
	End Sub

	Public Property Bar()
			...
		End Property
  End Class

  <Global.Microsoft.VisualBasic.HideModuleName()> _
  Friend Module CustomMyObjectModule
	Private instance As ThreadSafeObjectProvider(Of MyCustomMyObject)

	ReadOnly Property CustomMyObject() As MyCustomMyObject
	  Get
		Return instance.GetInstance()
	  End Get
	End Property
  End Module
End Namespace

كتابة التوسع

سنبدأ بتشغيل Visual Studio وإنشاء تطبيق كونسول جديد وتسميته MyValidation وأضافة Module جديدة للمشروع وتسميتها MyValidation.vb ثم استبدل كامل الكود الموجود بالكود التالي

Imports System.Text.RegularExpressions
Imports System
Imports System.Linq
Imports Microsoft.VisualBasic

Namespace My.Validation
  <Global.Microsoft.VisualBasic.HideModuleName()> _
  Public Module MyValidationMod
	Public Function IsEmpty(ByVal value As Object) As Boolean
	  If (value Is Nothing) OrElse _
		 (value Is System.DBNull.Value) OrElse _
		 (value.ToString = String.Empty) OrElse _
		 (TypeOf value Is Date AndAlso CDate(value) = Date.MinValue) _
	  Then
		Return True
	  Else
		Return False
	  End If
	End Function

	Public Function IsAlphaNumeric(ByVal value As String, _
	 Optional ByVal emptyOK As Boolean = False, Optional ByVal _
	 whitespaceOK As Boolean = False) As Boolean
	  If IsEmpty(value) Then Return emptyOK

	  Dim expr As String
	  If whitespaceOK Then
		expr = "^[a-zA-Z0-9\s]+$"
	  Else
		expr = "^[a-zA-Z0-9]+$"
	  End If

	  Return Regex.IsMatch(value, expr)
	End Function

	Public Function IsCanadianProvince(ByVal st As String) As Boolean
	  Dim allProv = "|AB|BC|MB|NB|NL|NT|NS|NU|ON|PE|QC|SK|YT"
	  Return st.Length = 2 AndAlso allProv.IndexOf("|" & st) <> -1
	End Function

	Public Function IsUSAState(ByRef st As String) As Boolean
	  Dim allStates = "|AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA|HI|ID|IL|IN|IA|" & _
		"KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|OH|" & _
		"OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY"
	  Return st.Length = 2 AndAlso allStates.IndexOf("|" & st) <> -1
	End Function

	Public Function IsUSAPostalCode(ByVal zip As String) As Boolean
	  If String.IsNullOrEmpty(zip) Then Return False

	  Return Regex.IsMatch(zip, "^\d{5}(-\d{4})?$")
	End Function

	Public Function IsCanadianPostalCode(ByVal zip As String) As Boolean
	  If String.IsNullOrEmpty(zip) Then Return False

	  Return Regex.IsMatch(zip, "^[A-Z]\d[A-Z] \d[A-Z]\d$")
	End Function

	Public Function IsNorthAmericanPhone(ByRef phone As String) As Boolean
	  If String.IsNullOrEmpty(phone) Then Return False

	  Dim expr As String = "^(?:\([2-9]\d{2}\)\ ?|[2-9]\d{2}" & _
						   "(?:\-?|\ ?))[2-9]\d{2}[- ]?\d{4}$"

	  Return Regex.IsMatch(phone, expr)
	End Function

	Public Function IsEmail(ByRef email As String) As Boolean
	  If String.IsNullOrEmpty(email) Then Return False

	  Dim localPartCharset = "[0-9a-zA-Z!#$%*/?|\^{}`~&'+\-=_]"
	  Dim domainPartCharset = "[0-9a-zA-Z\-]"
	  Dim expr = String.Format("^{0}+(\.{0}+)*@{1}+(\.{1}+)*", _ 
		localPartCharset, domainPartCharset)

	  Return Regex.IsMatch(email, expr)
	End Function
  End Module
End Namespace

عليك أن تكون حذرا عندما تقوم بإنشاء قالب My Extension يمكن أن يستخدم في تعريف أي مشروع فيجب عليك الانتباه بشكل خاص إلى القيم المحتملة لـ Option Explicit و Option Strict و Option Compare و Option Infer عندها يمكنك كتابة كودك ليعمل ضمن التعريف الأقل مرونة أو تحديد كل تعريف بشكل خاص في بداية كل ملف كود في توسعتك الذي يعتبر الأمر الأفضل.

كما يجب أن تأخذ إمكانية الاستيرادات المختلفة في المشاريع لتجنب التضارب في الرموز المعرفة على مستوى المشروع وهنا عليك تعديل أي رموز غير معرفة في قالبك بالكلمة المحجوزة Global أو My فمثلا بدلا من استخدام Text.Encoding استخدم Global.Text.Encoding فإن استخدمت Text.Encoding فقط فلن يعمل قالبك في تطبيقات Windows Forms التي ستستورد عندها مجالي أسماء مسميان Text فإن حذفت Global واستخدمت فقط System.Text.Encoding فربما لن يعمل قالبك الذي يحدد مجال أسماء يدعى System. ويعتبر اختبار كودك جيدا قبل توزيعه على الآخرين من الأفكار الجيدة ولا تشذ My Extensions عن هذه القاعدة.

دعنا نستخدم الـ Module التي تم إنشاؤها آليا باسم Module1 لكتابة تجربة لـ My Extensions ويجدر الانتباه إلى انه سيكون من الصعب إعادة استيراد التوسعات عندما تجد شائبة bug لذا عليك محاولة جعل التوسعة تعمل بشكل كامل قدر الإمكان والتأكد من أنها مختبرة جيدا قبل أن تقوم بتصديرها للمرة الأولى. قم بفتح Module1.vb وذلك بالنقر المزدوج عليها في Solution Explorer واستبدل الكود الموجود بالكود التالي ثم اضغط F5 لتشغيل المشروع

Module Module1
	Private testNumber As Integer
	Private testGroup As String

	Sub StartTestGroup(ByVal name As String)
		testGroup = name
		testNumber = 0
	End Sub

	Sub Test(ByVal result As Boolean, ByVal expected As Boolean)
		testNumber += 1

		If result <> expected Then
			Console.WriteLine("Test #{0} of group {1} FAILED.", _
			  testNumber, testGroup)
		End If
	End Sub

	Sub Main()

		StartTestGroup("IsAlphaNumeric")
		Test(My.Validation.IsAlphaNumeric("123HH2", True, True), True)


		StartTestGroup("IsCanadianPostalCode")
		Test(My.Validation.IsCanadianPostalCode("H0H 0H0"), True)


		StartTestGroup("IsCanadianProvince")
		Test(My.Validation.IsCanadianProvince("ON"), True)


		StartTestGroup("IsEmail")
		Test(My.Validation.IsEmail("a@b.com"), True)

		Console.WriteLine _
		  ("Tests are finished. No FAILED messages indicates success.")
		Console.WriteLine("Press any key to continue.")

		Console.ReadKey(True)
	End Sub
End Module

توضيب التوسعات كقوالب

بعد أن تمت كتابة التوسعة واختبرت بشكل كامل حان الوقت لتوضيبها كقالب My Extension. ولعمل ذلك اترك المشروع مفتوحا واختر الأمر Export Template من القائمة File فيظهر لك معالج Export Template حيث سنختار item Template من نافذة المعالج كما يتوفر لك خيار في الأسفل لاختيار اسم المشروع الذي سنصدر القالب منه ثم اضغط next ومن قائمة Item to export اختر MyValidation.vb ثم اضغط next ثم عليك اختيارا جميع المراجع الضرورية لعمل قالبك ومن أجل هذا المشروع اختر System.Core ثم اضغط next ثم املآ Template Description وقم بإزالة الإشارة عن الخيار Automatically import the template into Visual Studio الذي يجعل بيئة التطوير لا تقوم باستيراد القالب مباشرة بعد تصديره ثم اضغط Finish

My Extensions as Templates

في قالب My Extension كما هو الحال في جميع قوالب Visual Studio تكون جميع محددات القالب متوفرة وهي عبارة عن سلاسل نصية خاصة يمكن إدراجها آليا ضمن كود My Extension عندما يتم إضافتها للمشروع فـ $clrversion$ يتم استبدالها برقم النسخة الحالية لـ clr وفي حالة القالب Mu Extension سيتم استبدال $safeitemname$ بقيمة العنصر <DefaultName> في الملف الذي يحمل اللاحقة vstemplate والذي يساوي اسم الملف الذي يحوي كود القالب بدون لاحقته.

وأي شئ آخر يمكن عمله في قالب نظامي يمكنك عمله في القالب My Extension فضبط القيمة <Hidden> في الملف vstemplate إلى False يمكنك من إضافة القالب إلى صندوق الحوار Add New Item عندما تضيف العناصر للمشروع كما يمكنك إجبار إضافة مجمعات للمشروع عند إضافة القالب وذلك ضمن القسم <References> ويمكن إضافة عائلة من ملفات الكود عند انتهائها كالتي يتم إنشاؤها من قبل محرر نماذج ويندوز ذا بالإضافة إلى كود المستخدم.

كما توجد بعض الاختلافات الأساسية بين القوالب الأساسية وقوالب My Extensibility فلكي تمكن قالب العنصر Item Template كي يتم إدارتها من قبل صفحة My Extensions في مصمم مشاريع Visual Basic يجب عليك القيام بعدة خطوات لتعريفها بشكل ملائم.

في البداية يجب عليك إضافة العنصر <CustomDataSignature> للملف MyTemplate.vstemplate المتواجد في ملف zip الذي تم تصديره الذي يشير إلى أن قالب العنصر يجب معاملته كـ My Extension كما يجب عليك منع القالب من الفتح بشكل آلي عندما يتم إضافته للمشروع وذلك بإضافة بعض الصفات للعنصر <ProjectItem> بسبب أن كود MyExtension يجب أن يكون غير مرئي للمستخدم كما يجب عليك إضافة العنصر <Hidden> للملف MyTemplate.vstemplate كي لا يظهر القالب ضمن قائمة القوالب المثبتة عندما يختار المستخدم إضافة عناصر لمشروعه من خلال صندوق الحوار Add New Item وأخيرا عليك إضافة ملف باللاحقة customdata للرزمة وذلك لتوفير معلومات لا تنطبق على القوالب القياسية مثل unique Id و Version number و trigger assembly. ولعمل هذا عليك فك الملف ذو اللاحقة zip والقيام بالتعديلات المناسبة ثم إعادة ضغط الملفات الضرورية ثانية.

في البداية قم بفك محتويات القالب الذي قمنا بتصديره سابقا إلى مجلد فارغ ثم افتح الملف myTemplate.vstemplate وقم بالتعديلات كما في الكود

<VSTemplate Version="2.0.0"
   xmlns=http://schemas.microsoft.com/developer/vstemplate/2005
   Type="Item">
  <TemplateData>
	<DefaultName>MyValidation.vb</DefaultName>
	<Name>MyValidation</Name>
	<Description>Extends the My namespace with a set of string 
	   validation methods.</Description>
	<ProjectType>VisualBasic</ProjectType>
	<SortOrder>10</SortOrder>
	<Icon>TemplateIcon.ico</Icon>

	<!-- Configures the template to not be shown as an option 
	  when the user selects to add an item template to his project -->
	<Hidden>true</Hidden>

	<!-- Indicates it is to be treated as a My Extension. -->
	<CustomDataSignature>Microsoft.VisualBasic.MyExtension
	</CustomDataSignature>

  </TemplateData>
  <TemplateContent>
	<References>
	  <Reference> <Assembly>System.Core</Assembly> </Reference>
	</References>
	<ProjectItem SubType="Code" TargetFileName="$fileinputname$.vb"
	  ReplaceParameters="true" OpenInEditor="false"
	  OpenInWebBrowser="false" OpenInHelpBrowser="false">MyValidation.vb	 
	</ProjectItem>
  </TemplateContent>
</VSTemplate>

أنشئ ملفا جديدا - سوف نضيفه للرزمة لاحقا - وسمه MyValidation.customdata وافتحه بواسطة الـ Notepad وأضف إليه الكود التالي

<VBMyExtensionTemplate 
	ID="MyValidationMyNamespaceExtension" 
	Version="1.0.0.0" />

والواصفة AssemblyFullName التي تم حذفها في هذا المثال تشير إلى أنه عندما يتم إضافة هذا المجمع للمشروع فسوف يتم دعوة المستخدم لإضافة My Extension وعندما يزال المجمع من المشروع فسوف يتم دعوة المستخدم لإزالة My Extension ولإضافة مجمع قدح Trigger Assembly يمكن إضافة قسم كالتالي للملف customdata

<VBMyExtensionTemplate 
	ID="MyValidationMyNamespaceExtension" 
	Version="1.0.0.0"
	AssemblyFullName="System.Windows.Forms" />

قم الآن بإعادة نسخ جميع الملفات لداخل الملف zip باستخدام Windows Explorer

الملف vbproj

التعامل مع My Extension هو عملية مخفية آلية ولكي يقوم Visual Studio بمعالجتها بسلاسة باستخدام دخل قليل من المستخدم أصبح لملف المشروع الذي يحتوي على التوسعة بعض الصفات الجديدة التي يمكنك رؤيتها إذا قمت بفتح الملف ذو اللاحقة vbproj الخاص بالمشروع الذي قمت بإضافة التوسعة MyValidation إليه بأي محرر نصي فسوف ترى شيئا شبيها بالتالي

<ItemGroup>
  ...
  <Compile Include="My Project\MyExtensions\MyValidation.vb">
	<VBMyExtensionTemplateID>
	  MyValidationMyNamespaceExtension
	</VBMyExtensionTemplateID>
	<VBMyExtensionTemplateVersion>
	  1.0.0.0
	</VBMyExtensionTemplateVersion>
  </Compile>
  ...
</ItemGroup>

ولكن إذا ألقيت نظرة على القسم الخاص بملف كود أساسي مثل الملف Module1.vb فسوف ترى

<ItemGroup>
  <Compile Include="Module1.vb" />
</ItemGroup>

وكما ترى هناك بعض الاختلافات فالملف MyValidation.vb سوف يتم تخزينه في مجلد المشروع وهذا يعني أنه سوف يكون غير مرئي إلا إذا فعلت خيار Show All items في Solution Explorer وستجد أن له قطعتان إضافيتان من البيانات توافق القيم المضافة في الملف MyValidation.customdata. وبتخزين هذه المعلومات يمكن لـ Visual studio أن يسمح للمستخدم بإضافة وإزالة التوسعات من صفحة My Extensions في خصائص المشروع بدلا عن إضافة الملف بشكل يدوي وإن كان هناك مؤشر لمجمع قادح وتمت إزالته فسيقوم لـ Visual Studio بتحذير المستخدم من أن My Extension لن يستطيع العمل ويعطيه خيارا لإزالته كما تمنع من تواجد أكثر من نسخة من التوسعة في نفس المشروع.

مترجم بتصرف

عن عائشة رضي الله عنها أن النبي صلى الله عليه وسلم قال: إن الله يحب إذا عمل أحدكم عملا أن يتقنه

نعيب زماننا والعيب فينا ... وما لزماننا عيب سوانا

ونهجو ذا الزمان بغير ذنب ... ولو نطق الزمان لنا هجانا

محمد سامر أبو سلو

#2

أشكرك عزيزي درس رائع ..

get-4-2008-emk00cr6.png

للمراسلة : BG.W@hotmail.com

BG.WALEED@yahoo.com

مواضيع مشابهة