منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب

نسخة كاملة : مقال - تطوير الكونترول - إضافة Smart Tags
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
كاتب الموضوع : silverlight

الموضوع : تطوير الكونترول - إضافة SmartTags
اللغة المستخدمة: الفيجوال بيسك
التطبيق: فيجوال استوديو 2005 و 2008
المستوي: التقييم متروك للقارئ
إعداد: مهندس / عمر أمين إبراهيم

ماذا تعني هاتان الكلمتان Smart Tags ظهرت هاتان الكلمتان حديثا وتم استخدامها علي نطاق واسع في الأوفيس 2003 وتم دعم هذه السمة برمجيا في الفيجوال استوديو 2005 تحديدا. وهي عبارة عن Panel تظهر بجوار الكونترول وذلك عند الضغط علي Button يظهر بشكل سهم صغير في أقصي يمين الكونترول وعندما تظهر هذه Panel فإننا نري بعض الاختيارات المختلفة التي يمكن من خلالها التحكم في خواص الكونترول.
إن أفضل مثال من الممكن إعطاؤه لتوضيح خاصية Smart Tags هو DataGridView
في الواقع إن أفضل مثال توضيحي لإضافة Smart Tags الي الكونترول الذي نقوم بتصميمه هو أن نفعل ذلك بشكل عملي مباشرة وسوف أحاول أن يكون المثال الأول بسيط جدا لكي يتمكن القارئ من المتابعة بسهوله واقصد هنا تحديدا المبتدئين في دنيا البرمجة.
الخطوات:
تعتمد الخطوات ببساطه شديدة علي ثلاثة مراحل أساسيه. المرحلة الأولي وهي كتابة الكونترول أو تصميمه والمرحلة الثانية إضافة Action List والمرحلة الثالثة وهي إضافة Control Designer وأخيرا إضافة Attributes وذلك يتم علي مراحل مختلفة أثناء كتابة الكود

Control Design Class
Action List Class
Designer Class
Attributes

كبداية سوف نستخدم مشروع عادي ألا وهو Windows Forms Application وليكن اسم المشروع SmartTagsSampleProject والخطوات التالية توضح الامر.
افتح مشروع جديد ثم اختار Windows Forms Application وأعطي للمشروع اسم SmartTagsSampleProject
: أول شئ سوف نقوم بعمله بعد ذلك هو إضافة Reference مهم جدا للمشروع وذلك يتم بالوقوف في نافذة Solution Explorer والضغط علي أيقونة Show All Files ثم الوقوف بالماوس علي References واضغط يمين الماوس ثم اختار Add Reference…
ومن تحت .Net نبحث عن System.Design ونختاره ثم نضغط OK وبذلك نكون قد أضفنا هذا Reference الهام.

وقد يتساءل البعض ما هذا الذي أضفناه للمشروع وما الغرض منه تحديدا في الواقع الاسم الكامل لهذا Reference هو System.Windows.Forms.Design وهو Namespace يحتوي علي مجموعه من الكلاس المختلفة التي تختص بالتعامل مع الكونترول أو الفورم في مرحلتي التصميم Design Time و Run Time ولمن يريد تفاصيل أكثر عن هذا الكلاس فيمكنه الرجوع الي Help Files أو البحث علي التت أو الدخول علي مواقع ميكروسوفت أو بآي طريقه يراها مناسبة.

إن ما بهمنا مرحليا في هذا Namespace هو ParentControlDesigner وهو ما سوف نستخدمه لكي نضيف الي الكونترول بعض السمات التي نريدها مثل Smart Tags وطبعا فيه Classes أخري داخل هذا Namespace يمكن استخدامها لإضافة Smart Tags ولكني كما أوضحت سوف استخدم هنا فقط ParentControlDesigner .

ألان نضيف الي المشروع كلاس جديد اسمه SmartTagsControl ثم نضيف الي الكلاس كونترول عن طريق استخدام Inherits أو الوراثة فيكون الكود لدينا كالتالي


كود :
Public Class SmartTagsControl
Inherits Control
End Class
الأن نضيف تعريف جديد للتعبير عن اللون ولنطلق عليها اسم _XColor وأيضا نضيف الي الكونترول Public Property جديدة ولنطلق عليها XColor ثم نضيف بعض Attributes الي الصفة XColor فيكون الكود كالأتي

كود :
Imports System.ComponentModel
Public Class SmartTagsControl
Inherits Control
Private _XColor As Color = Nothing ' or you can set default value like Color.Blue

<Browsable(True), Description("XColor replace the control backColor Property"), Category("Xtra Appearance")> _
Public Property XColor() As Color
Get
Return _XColor
End Get
Set(ByVal value As Color)
If (value <> _XColor) Then
_XColor = value
End If
End Set
End Property

End Class
لنتوقف هنا قليلا لنفسر ماحدث في هذا الجزء من الكود
أولا تم إضافة Import لأحدي Namespaces و هي System.ComponentModel وهو يتعامل مع الكونترول Behaviour في مرحلة التصميم Design وايضا في مرحلة Run Time
ثانيا تم إضافة بعض Attributes وهو عبارة عن Behaviour أو تعريف السلوك للصفة التي انشئناها ألا وهي XColor
<Browsable(True), Description("XColor replace the control backColor Property"), Category("Xtra Appearance")> _
وهنا لنأخذ كل جزء علي حده لتوضيحه
الجزء Browsable(True) هنا نطلب ان تكون هذه الصفه ظاهره للمبرمج في Properties Window اي في مرحلة التصميم ويمكن ايقاف ظهور الخاصيه في مرحلة التصميم عن طريق تغيير الكلمه True الي False
الجزء Description("XColor replace the control backColor Property") هو مجرد جزء نوضح فيه الهدف من هذه الصفه يعني ببساطه نوع من المساعده Help السريعه اي عندما يقف المبرمج بالماوس علي هذه الصفه في مرحلة التصميم سيظهر ما كتبناه بين
الاقواس كنوع من التعريف لهذه الخاصيه التي قمنا بانشاؤها في اسفل Properties Window
الجزء Category("Xtra Appearance")> عباره عن تصنيف للصفه التي اضفنها داخل Properties Window

ملحوظه أخيره طبعا بحسب رؤية المبرمج أو المطور وباستخدام Attributes ممكن أن نقوم بعدم إظهار أي صفه تخص الكونترول بشكل عام في Properties Window ولإعطاء مثال علي ذلك سنقوم بإخفاء خاصية ForeColor الموجودة مع الكونترول
طبعا هناك طريقه أخري للتخلص من أي صفه بشكل نهائي وسيتم مناقشة ذلك لاحقا
و الكود التالي سيكون الكود النهائي للكونترول الذي نريد تطويره ويتبقي بعض الإضافات القليلة لكي نقوم بإظهار Smart Tags ولكن سنقوم بإضافتها لاحقا وذلك بعد الانتهاء من الأجزاء الاخري للكلاس


كود :
Imports System.ComponentModel
Public Class SmartTagsControl
Inherits Control
Private _XColor As Color = Nothing ' or you can set default value like Color.Blue
<Browsable(True), Description("XColor replace the control backColor Property"), Category("Xtra Appearance")> _
Public Property XColor() As Color
Get
Return _XColor
End Get
Set(ByVal value As Color)
If (value <> _XColor) Then
_XColor = value
End If
End Set
End Property

<Browsable(False)> _
Public Overrides Property ForeColor() As Color
Get
Return _XColor
End Get
Set(ByVal value As Color)
If (value <> _XColor) Then
_XColor = value
End If
End Set
End Property
End Class
الأن سوف نضيف Public Class أخر باسم SmartTagsControlActionList
وهنا سوف أفتح كلاس جديد حتى لا يحدث تضارب للقارئ و الأن نضيف DesignerActionList الي الكلاس عن طريق الوراثة وأيضا يتم عمل Import لبعض Namespaces وهي System.ComponentModel.Design وأيضا System.ComponentModel مع مراعاة اضافة Constructor للكلاس الذي اضفناه عن طريق الوراثه والمقصود هنا بكلمة Constructor هو اضاقة Public Sub New وهذا ضروري جدا لان هذا Constructor هو الذي سيقوم بربط Smart Tags بالكونترول الذي صممناه سابقا وبذلك يكون الكود لدينا قد اصبح بالشكل الاتي


كود :
Imports System.ComponentModel.Design
Imports System.ComponentModel
Public Class SmartTagsControlActionList
Inherits DesignerActionList
Public Sub New(ByVal component As IComponent)
MyBase.New(component)
End Sub
End Class
الأن سوف نقوم ياضافة متغيرين الي الكلاس احدهما يخص الكونترول الذي قمنا بتصميمه سابقا وهو SmartTagsControl والأخر يخص DesignerActionUIService وهو ببساطه شديده يعتبر المدير الذي يدير Smart Tags Panel ثم نقوم بعمل تنشيط Refresh من اجل DesignerActionList فيصبح الكود لدينا كالتالي


كود :
Imports System.ComponentModel.Design
Imports System.ComponentModel
Public Class SmartTagsControlActionList
Inherits DesignerActionList
Private designerActionUISvc As DesignerActionUIService = Nothing
Private smtagControl As SmartTagsControl
'Constructor associates the control with the smart tag list.
Public Sub New(ByVal component As IComponent)
MyBase.New(component)
Me.smtagControl = component
' Refresh DesigneractionList.
Me.designerActionUISvc = _
CType(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
End Sub
End Class
الأن سوف نضيف Function والهدف منها هو استرجاع ٍالصفات الخاصة بالكونترول الذي أنشئناه وهو SmartTagsControl ونستخدم فيها PropertyDescriptor كلاس
وأيضا نضيف الي هذا الكلاس الصفات Properties التي نريد إظهارها في Smart Tags الخاصة بالكونترول الذي صممتاه ولتكن علي سبيل المثال الصفة الوحيدة التي أضفناها الي الكونترول وهي XColor مع ملاحظة أنها ستضاف بشكل مختلف قليلا عن الخاصية الاصليه الموجودة في الكونترول الذي أنشئناه
ثم نأتي الي الخطوة الأخيرة للانتهاء من هذا الكلاس سنقوم بعمل Overrides لأحدي Functions الموجودة في الكلاس DesignerActionList والهدف من ذلك استرجاع Collections الخاصة بالأغراض الموجودة في DesignerActionItems وبذلك يكون الكود النهائي لهذا الكلاس كالأتي وهنا يجب أن نكون حذرين قليلا في كتابة Strings تحديدا حيث يجب أن يكون كل جزء في مكانه الصحيح لان كل شئ هنا سوف يعتمد علي Strings أو Text وذلك لكي يعمل Smart Tags بالشكل المطلوب


كود :
Imports System.ComponentModel.Design
Imports System.ComponentModel
Public Class SmartTagsControlActionList
Inherits DesignerActionList
Private designerActionUISvc As DesignerActionUIService = Nothing
Private smtagControl As SmartTagsControl
'Constructor associates the control with the smart tag list.
Public Sub New(ByVal component As IComponent)
MyBase.New(component)
Me.smtagControl = component
' Refresh DesigneractionList.
Me.designerActionUISvc = _
CType(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
End Sub
' use the function to retrieve SmartTagsControl properties.
Private Function GetPropertyByName(ByVal propName As String) As PropertyDescriptor
Dim prop As PropertyDescriptor
prop = TypeDescriptor.GetProperties(smtagControl)(propName)
If prop Is Nothing Then
Throw New ArgumentException("Matching XtraPanel property not valid!", propName)
Else
Return prop
End If
End Function
Public Property XColor() As Color
Get
Return smtagControl.XColor
End Get
Set(ByVal value As Color)
GetPropertyByName("XColor").SetValue(smtagControl, value)
End Set
End Property
' Returns the collection of DesignerActionItem objects contained in the list
Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection
Dim items As New DesignerActionItemCollection()
'Define First static section header entries.
items.Add(New DesignerActionHeaderItem("Xtra Appearance"))
' First Item to be Listed under the First Header Section
items.Add(New DesignerActionPropertyItem("XColor", _
"XColor", _
"Xtra Appearance", _
"Temporary Smart Tags"))
Return items
End Function
End Class
تعليق أخير قبل البدء في الكلاس الثالث ويخص بالتحديد السطر التالي في الكود السابق وهو
'Define First static section header entries.
items.Add(New DesignerActionHeaderItem("Xtra Appearance"))
لو مطلوب إضافة اكتر من Static Header يتم استخدامه بنفس ألطريقه مع تغيير الاسم الموجود بين الأقواس ومثال لذلك
'Define First static section header entries.
items.Add(New DesignerActionHeaderItem("Xtra Appearance"))
'Define Second static section header entries.
items.Add(New DesignerActionHeaderItem(" الاسم الثاني الذي تريد كتابته "))
'Define static section header entries.
items.Add(New DesignerActionHeaderItem(" الاسم الثالث الذي تريد كتابته "))
وبالمثل لإضافة Items مختلفة تحت كل Header نتبع الأتي
' First Item to be Listed under the First Header Section
items.Add(New DesignerActionPropertyItem("XColor", _
"XColor", _
"Xtra Appearance", _
"Temporary Smart Tags"))
' First Item to be Listed under any Header Section
items.Add(New DesignerActionPropertyItem("اسم property", _
"الاسم الذي تريدان يظهر امام الصفه", _
"ٍاسم Header", _
"وصف عام للصفه"))

الأن سوف نضيف Public Class أخر باسم SmartTagsControlDesigner وهنا أيضا سوف أفتح كلاس جديد تماما حتى لا يحدث تضارب للقارئ
إن أهم الأشياء التي يجب إضافتها الي هذا الكلاس هي Security Permission Attribute وبالتالي فان علينا أن نقوم بعمل Import لبعض Namespaces وهي System.Security.Permissions و System.Windows.Forms.Design وايضا System.ComponentModel.Design وحيث اننا سوف نقوم عن طريق استخدام الوراثه Inherits سوف نقوم باضافة ايضا ParentControlDesigner واخير نضيف متغير وهو يخص DesignerActionListCollection ثم نقوم بعمل Overrides لاحدي Public ReadOnly Property وهي ActionLists وهي خاصيه او Property تخص بالتحديد ParentControlDesigner والكود التالي يوضح كل ذلك


كود :
Imports System.Security.Permissions
Imports System.Windows.Forms.Design
Imports System.ComponentModel.Design
<PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
Public Class SmartTagsControlDesigner
Inherits ParentControlDesigner
Private lists As DesignerActionListCollection
Public Overrides ReadOnly Property ActionLists() As System.ComponentModel.Design.DesignerActionListCollection
Get
If lists Is Nothing Then
lists = New DesignerActionListCollection()
lists.Add(New SmartTagsControlActionList(Me.Component))

End If
Return lists
End Get
End Property
End Class
أخر شئ يجب إضافة Attribute الي الكونترول الأصلي وذلك لتحديد Designer الذي سيقوم الكونترول باستخدامه وكل المطلوب إضافة سطر واحد فقط قبل SmartTagsControl وبذلك يكون الشكل النهائي للكود كالأتي


كود :
Imports System.ComponentModel
<Designer(GetType(SmartTagsControlDesigner))> _
Public Class SmartTagsControl
Inherits Control
‘ هنا يكتب باق الكود كما في الكلاس اعلاه في اول الموضوع
End Class
الأن نستطيع أن نقوم بعمل Build للكونترول وسنراه موجودا في Toolbox وبالتالي نستطيع إضافته الي الفورم والتعامل معه ولكن حتى الأن لم نستفد من الخاصية التي أضفناها وأيضا سوف نري أن Smart Tags أصبحت خاصية متاحة مع الكونترول وأيضا الصفة ForeColor لم تعد ظاهره عند التعامل مع الكونترول من خلال Properties Windows ولكن لم يتم إلغاؤها تماما فهي خاصية متاحة يمكن الدخول لها من الكود فقط ولو أحببنا إلغاء احدي Property الخاصة بالكونترول تماما فانه علينا أن نقوم بعمل Overrides لأحدي الطرق Methods الموجودة داخل ParentControlDesigner وهي PostFilterProperties وبذلك يتم اضافة الكود التالي الي SmartTagsControlDesigner


كود :
Protected Overrides Sub PostFilterProperties(ByVal Properties As IDictionary)
' let us remove some of the posted properties of the control

Properties.Remove("BackgroundImage")
Properties.Remove("BackgroundImageLayout")
Properties.Remove("BorderStyle")
Properties.Remove("Font")
Properties.Remove("Padding")

End Sub
بالتوفيق
احوكم عمر