الأنواع الأخرى من الصفات Properties التي تخص ParentControlDesigner كلها موجودة في ControlDesigner Class أي أنهم يشتركان معا في هذه الصفات ولكي نكتب عنها جميعا سنحتاج الي الكثير من الوقت والجهد ولأن بعض هذه الصفات لا يحتاج الي أن نقوم بالتعديل بها لذلك سنقوم بالتركيز علي الصفات والطرق التي تهمنا لكي نقوم بتصميم Custom Control
ActionLists Property
هذه الصفة تهمنا جدا لأنه من خلالها نستطيع استرجاع مجموعة من Action Lists التي تخص أي Property قمنا بإضافتها الي DesignerActionList Class وهذا الكلاس هو الذي يتعامل تحديدا مع Smart Tags أو من خلاله نستطيع أن نضيف Smart Tags الي الكونترول الذي نصممه ومن ثم
نستطيع أن نسترجع كل الصفات التي وضعناها في هذا الكلاس ونربط بينها وبين الكونترول الذي نصممه من خلال استخدام هذه الخاصية ActionLists Property
إذن لكي نستخدم هذه الخاصية علينا أن نضيف كلاس جديد تماما الي مشروعنا وليكن اسم هذا الكلاس MyActionLists Class ثم نضيف له DesignerActionList Class عن طريق Inherits ونضيف إليه الصفات التي نريد أن نستخدمها مع الكونترول والتي تظهر في صورة Smart Tags وبعد ذلك نقوم بعمل Overrides لهذه الصفة ActionLists Property من داخل MyDesigner Class لكي نسترجع الصفات الموجودة داخل MyActionLists Class
انظر المثال المرفق الي هذا المقال أو الي المثال الموجود تحت المقال المكتوب عن تطوير الكونترول Smart Tags
SelectionRules Property
عندما نضيف أي كونترول الي أي فورم مثلا فإننا نستطيع التحكم به من خلال الماوس أي نستطيع نقله من مكان الي مكان داخل الفورم نستطيع أيضا تغيير أبعاده مثل ارتفاعه أو عرضه باستخدام الماوس وهذه الخاصية مسئولة عن ذلك أو هي التي نحدد من خلالها كيفية التحكم في حركة الكونترول وأيضا المناطق التي من خلالها يستطيع المستخدم التحكم في أبعاد للكونترول في مرحلة التصميم باستخدام الماوس وذلك بالإضافة الي متغيرات أخري وهذه المتغيرات مصنفة كالأتي
None, Movable, Visible, Locked, TopSizeable, BottomSizeable, LeftSizeable, RightSizeable, AllSizeable وكما نلاحظ أن هذه المتغيرات جميعها عبارة عن Enum
نفرض مثلا انك تريد منع المستخدم من تحريك الكونترول إذن تستطيع أن تقوم بعمل Overrides لهذه الخاصية واستخدام Locked
كود :
Public Overrides ReadOnly Property SelectionRules() As System.Windows.Forms.Design.SelectionRules
Get
Return SelectionRules.Moveable Or Windows.Forms.Design.SelectionRules.Visible
End Get
End Property
Verbs Property
ماذا تعني هذه الصفة؟ لأوضح أهمية الصفة سوف أعطي مثالا سريعا عندما نضيف الي الفورم أي كونترول أخر مثل DataGridView مثلا وكلنا يعلم أن هذا الكونترول يمتلك بعض Smart Tags بعضها عبارة عن Property وبعضها عبارة عن اختيارات أخري مثل LinkLabel أو Hyperlinks ولو نظرنا الي Properties Windows سنجد بعض هذه اللينك موجودة هناك في الأسفل ولو وقفتا بالماوس علي DataGridView ثم ضغطنا يمين الماوس سيظهر لنا أيضا ContextMenu وهنا سنجد أن بعض Smart Tags موجودة بالفعل داخل ContextMenu وعند الضغط علي أي لينك سوف يحدث حدث ما في الواقع هذه الصفة هي المسئولة عن ذلك والرائع في هذه الصفة أنها تضيف LinkLabel Smart Tags أوتوماتيكيا الي Smart Tag Panel وأيضا الي ContextMenu
كيف يمكننا أن نقوم بإضافة Verbs الي الكونترول الي نقوم بتصميمه.
أن ذلك يتم عن طريق عمل Overrides لهذه الخاصية ومن ثم نضيف متغير عبارة عن DesignerVerbCollection Class ونستخدمه لإضافة ما نريد من اللينك مع إضافة EventHandler تربط اللينك بحدث ما
كود :
Public Overrides ReadOnly Property Verbs() As System.ComponentModel.Design.DesignerVerbCollection
Get
Dim m_verbs As New DesignerVerbCollection()
m_verbs.Add(New DesignerVerb("Dock Fill", New EventHandler(AddressOf OnArabDemoDockFillEvent)))
m_verbs.Add(New DesignerVerb("Message..", New EventHandler(AddressOf OnArabDemoMessageEvent)))
Return m_verbs
End Get
End Property
' new EventHandler
Private Sub OnArabDemoDockFillEvent(ByVal sender As Object, ByVal e As EventArgs)
Me.Control.Dock = DockStyle.Fill
End Sub
' EventHandler
Private Sub OnArabDemoMessageEvent(ByVal sender As Object, ByVal e As EventArgs)
MessageBox.Show("Hello All Arabs", "Message", MessageBoxButtons.OK)
End Sub
PostFilterProperties
هل فكرت يوما أن تقوم بإلغاء أو تعديل بعض الصفات الموجودة مع الكونترول أعتقد إن بعض القراء فكروا في الأمر عموما هذا ممكن عن طريق عمل Overrides الي PostFilterProperties Sub لكن من الأفضل أن لا نلغي أي صفة Property من صفات الكونترول لأن بعض الصفات مرتبطة مع بعضها البعض عن طريق Attribute ولكن أنصحك أن تقوم بعمل Override من داخل الكونترول الذي تقوم بتصميمه مع ضبط خاصية BrowsableAttribute الي False وبذلك تضرب عصفورين بحجر أي نستفيد بأن الصفة مازالت موجودة وبالتالي ممكن للمبرمج استخدامها في أي وقت يشاء من داخل الكود فقط مع أيضا إمكانية عدم ظهورها للمستخدم في مرحلة Design وبشكل عام لو أردت عزيزي القارئ أن تقوم بإلغاء بعض الصفات نهائيا فإن ذلك يتم طبقا للكود التالي
كود :
Protected Overrides Sub PostFilterProperties(ByVal Properties As IDictionary)
Properties.Remove("BackgroundImage")
Properties.Remove("BackgroundImageLayout")
End Sub
PreFilterProperties
هذا Sub يستخدم في إضافة صفات الي الكونترول لكي يتم استخدامها في مرحلة التصميم فقط وهي مرتبطة بخاصية أخري يمكننا من خلالها من الرسم في الكونترول في مرحلة التصميم فقط وهي OnPaintAdornments والكود التالي يوضح الأمر.
كود :
Private MyDesignColor As Color = Color.Blue
Public Property DesignColor() As Color
Get
Return MyDesignColor
End Get
Set(ByVal Value As Color)
MyDesignColor = Value
End Set
End Property
Protected Overrides Sub PreFilterProperties(ByVal properties As System.Collections.IDictionary)
Dim descriptor As PropertyDescriptor = _
TypeDescriptor.CreateProperty(GetType(myDesigner), "DesignColor", _
GetType(System.Drawing.Color), _
New Attribute() {New DesignOnlyAttribute(True)})
properties.Add("DesignColor", descriptor)
End Sub
OnPaintAdornments
هذا Sub يستخدم في رسم أي شئ داخل الكونترول وهو في مرحلة Design وعند التشغيل تختفي هذه الرسومات التي هي أحيانا مجرد تحديد لأبعاد الكونترول الخارجية مثلا ممكن نلاقي مرسوم Rectangle حول الكونترول وعند اختيار الكونترول فإن اللون المرسوم به المستطيل يكون في حالة Active وعندما نترك الكونترول ونختار أي كونترول أخر موجود داخل الفورم مثلا فان هذا المربع يتحول لونه الي حالة Inactive ومع ذلك مازلنا نراه في الفورم وأيضا عند التشغيل للمشروع يختفي ه1ا المربع ولا نراه إذن الأمر واضح هذا Sub يقوم برسم أي شئ داخل الكونترول ولمن يعرف كيفية التعامل مع GDI+ فإن هذا Sub يشبه تماما Form_Paint مثلا أو Panel_Paint إذن فهو يؤدي نفس الوظيفة مع الكونترول ولكن في مرحلة Design فقط وبالتالي عند استخدام هذا Sub يجب علينا أن نتعامل مع حركة الماوس أيضا مثل OnMouseEnter و OnMouseLeave وهكذا يعني ببساطه هذا Sub يتيح لنا أن نزين ونجمل ونضيف ديكور للكونترول حتى وهو في مرحلة التصميم مع الوضع في الاعتبار أن كل ما سوف يرسم سوف يختفي تماما عند التشغيل ويظهر فقط في مرحلة التصميم المثال التالي يوضح كيفية التعامل مع الامر طبعا تستطيع عزيزي القارئ أن ترسم ما تريد طبقا لمتطلباتك وخيالك. ومن عنده فكره جيده عن GDI+ يستطيع أن يبدع في هذا الأمر لكني أنصحك عزيزي القارئ أن تجعل الرسم في مرحلة التصميم بسيط جدا بقدر الإمكان حثي لا تشتت المبرمج الذي سوف يستخدم الكونترول الخاص بك.
كود :
Private mousemotion As Boolean = False
Protected Overrides Sub OnPaintAdornments(ByVal pe As System.Windows.Forms.PaintEventArgs)
Dim OuterRect As Rectangle = New Rectangle()
OuterRect = Me.Control.ClientRectangle
Dim InnerRect As Rectangle = Rectangle.FromLTRB(OuterRect.X + 2, OuterRect.Y + 2, OuterRect.Width - 2, OuterRect.Height - 2)
If mousemotion Then
' ^_^ First Method
ControlPaint.DrawFocusRectangle(pe.Graphics, OuterRect)
Else
' ^_^ Second rect
pe.Graphics.DrawRectangle(Pens.Blue, InnerRect)
End If
End Sub
Protected Overrides Sub OnMouseLeave()
Me.mousemotion = False
Me.Control.Refresh()
End Sub
Protected Overrides Sub OnMouseEnter()
Me.mousemotion = True
Me.Control.Refresh()
End Sub
طبعا لو أردنا أن نستمر في طرح كل ما يخص Designer من صفات وطرق وغيرها فإن المقال سيتحول الي كتاب ضخم ولكن الهدف هنا هو كيفية السبيل الي التطوير وماذا نحتاج لكي نقوم بتطوير كونترول بشكل احترافي و أعتقد أن هذه المقالات ستكون فقط بمثابة مدخل أو خطوط عريضة الهدف منها فقط عزيزي القاري أن تكون بمثابة البداية لكي تبحث في الأمر بنفسك .
تبقي شئ أخير وهذا الأمر تركته للنهاية لأهميته القصوى وأنا أتصور أن الكثير منكم لا يعلمون عنه شيئا لأن لا أحد يتحدث عنه مطلقا ولكي تجد بيانات عنه يجب أن تعرفه أولا وطبعا إذا كنت تجهله عزيزي القارئ فكيف ستبحث عنه.
كل المبرمجين يعلمون ما هو ClientRectangle Area وأيضا NonClientRectangle Area السؤال الأن كيف نحدد ذلك في الكونترول الذي نقوم بتصميمه؟ هذا السؤال ربما دار بعقل الكثيرين والشيء الغريب أن لا حدا يتحدث عنه علي الإطلاق وحتى لو قمت بالبحث سوف تجد إجابات غير واضحة تماما ولربما تجعلك هذه الإجابات تدخل في متاهة كبري وتؤدي بك الي أبواب مسدودة.
أكرر السؤال كيف نحدد المنطقة التي تسمي بمنطقة NonClientRectangle ؟
الإجابة علي هذا السؤال بسيطة جدا ولربما تجعلك عزيزي القارئ تفعل كما فعل أرشميدس يوما وخرج عاريا وهو يقول وجدتها Eureka .
الإجابة تكمن في كلمة واحدة وهي :الأتي
DisplayRectangle
وهذه خاصية Read-Only Property من خواص Control Class وبما أن كل شئ مشتق من الكونترول حتى الفورم مشتق من الكونترول و لكي نقوم بالتغيير في هذه Property من الأفضل أن نربطها بصفة أخري وهي ClientRectangle Property والمثال التالي يوضح كيف نقوم بعمل Overrides لهذه الصفة.
كود :
Public Overrides ReadOnly Property DisplayRectangle() As Rectangle
Get
display_rectangle.X = ClientRectangle.X + 5
display_rectangle.Y = ClientRectangle.Y + 24
display_rectangle.Width = ClientRectangle.Width - 10
display_rectangle.Height = ClientRectangle.Height - 42
Return display_rectangle
End Get
End Property
الخلاصة Conclusion
لكي تستطيع التطوير ولكي تكون Developer ناجحا عليك بالأتي:-
إبحث في أصل كل كلاس تقابله وستكتشف أن من السهل أن تكتب أي كلاس وسوف نوضح ذلك في الجزء القادم من سلسلة مقالات تطوير الكونترول الذي سوف يغطي VisualStyleRenderer Class.
استخدم الكونترول الموجودة ولا تحاول أن تبني الكونترول من الصفر وإلا ستحتاج لكتابة الكثير والكثير من الكود.
تعلم GDI+ وتعلم أن تتقنها جيدا فهي المسئولة عن كيفية الرسم داخل أي كونترول.
اتمني ان يكون الموضوع واضح وبخصوص المثال الذي وعدت به قسوق اضعه اليوم او غدا بالمنتدي
بالتوفيق
اخوكم عمر