![]() |
|
تطوير الكونترول Designers الجزء الرابع - نسخة قابلة للطباعة +- منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب (http://vb4arb.com/vb) +-- قسم : قسم لغة الفيجوال بيسك VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=182) +--- قسم : قسم مقالات VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=184) +--- الموضوع : تطوير الكونترول Designers الجزء الرابع (/showthread.php?tid=4969) |
تطوير الكونترول Designers الجزء الرابع - RaggiTech - 03-10-12 كاتب الموضوع : silverlight
الموضوع : تطوير الكزنترول Designers اللغة المستخدمة: الفيجوال بيسك التطبيق: فيجوال استوديو 2005 و 2008 المستوي: التقييم متروك للقارئ إعداد: مهندس / عمر أمين إبراهيم ماذا تعني كلمة Designers ؟ هذا سؤال مهم جدا نسأله لأنفسنا وطبعا ليس المقصود هنا أن نترجم المعني من الإنجليزية الي العربية عموما لكي نجيب علي السؤال فالإجابة ستكون كالأتي إن Designers هي همزة الوصل بين المبرمج و الكونترول بأنواعه المختلفة في مرحلة Design Time. بشكل عام Designers يمكن استخدامها مع Windows Forms وأيضا مع Web UI ما هي أنواع Designers ؟ هناك العديد من Designers و هي مرتبه حسب أنواعها كالأتي ComponentDesigner Class ControlDesigner Class ComponentDocumentDesigner Class ParentControlDesigner Class ScrollableControlDesigner Class DocumentDesigner Class وعموما كل هذه الكلاس Classes مشتقه من بعضها البعض والأصل لجميعها هو ComponentDesigner الذي يتكون من مجموعه من Interfaces التي تمثل أصل Designers Classes أصل Designer ؟ جميع أنواع Designers المعروفة لنا جاءت من مكان واحد فقط ألا وهو مجموعه من Interfaces وهي كالأتي IDesigner Interface IDisposal Interface IDesgnerFilter Interface ITreeDesigner Interface IComponentInitializer Interface IRootDesigner Interface IToolboxUser Interface ITypeDescriptorFilterServices Interface ولمزيد من التفاصيل يمكن الرجوع الي Namespaces التالية System.Windows.Forms.Design Namespace System.ComponentModel.Design Namespace نبذة عن الكونترول كما تعلمون إن الكونترول له أنواع مختلفة كثيرة وكلها مشتقه من Control Class ومنها علي سبيل المثال الأنواع التالية Control Class وهذا النوع هو ما يختص به موضوعنا عن تطوير الكونترول وهو مشتق من Component Class الذي بدوره مشتق من MarshalByRefObject Class ScrollableControl Class وهو مشتق من Control Class ContainerControl Class وهو مشتق ScrollableControl ListControl Class وهو أيضا مشتق من Control Class وهذا النوع من الكونترول هو الذي تم استخدامه في بناء الكومبو بوكس ComboBox Class و أيضا ListBox Class الفارق بين هذه Control Classes المختلفة انه قد تم عمل Implementation لبعض Interfaces أي انه قد أضيفت بعض Interfaces وبناء عليه يتم تخليق Control Class باسم جديد فقط وطبعا أنت أيضا عزيزي القارئ يمكنك أن تفعل نفس الشيء يعني ببساطه تقدر تخلق أي كلاس بأي اسم تريد وتضيف له مواصفات جديدة عن طريق استخدام Interfaces أو يدون Interfaces أعتقد الأن أدركت عزيزي القارئ لماذا تطرقنا لمناقشة موضوع Interfaces ولإعطاء مثال عام عن موضوعنا انظر الي الكود الموجود أدناه. وفي هذا المثال قمت باستخدام Attribute وهو عبارة عن System.Windows.Forms.Design. DocumentDesigner وهذا يوضح كيفية اسخدام Designers الموجوده في System بدون اضافة اي Custom Designers واستعمالها في نصميم الكونترول. كود : Imports System.ComponentModelتطوير الكونترول Designers الجزء الرابع - RaggiTech - 03-10-12 ملحوظه هامه عن الكونترول كلاس الكونترول يمتلك مجموعه من الصفات Properties وهي صفات أوليه كلها تبدأ باسم Default مثل خاصية DefaultSize و DefaultFont وأيضا بعض الخواص الاخري وطبعا ممكن عمل Overrides لهذه الصفات جميعا لو أردنا وذلك حسب متطلبات الكونترول الذي نقوم بتصميمه. كيف تصنع Designer ؟ الإجابة علي هذا السؤال تنحصر في الخطوات التالية: لتصنع Designer فأنت بحاجه الي كونترول أولا أي يجب أن تصنع الكونترول الخاص بك مهما كان نوعه أو شكله أو الهدف منه أيضا أنت بحاجه الي إضافة Reference هام جدا إلي مشروعك وهو Namespace: System.Windows.Forms.Design ولكي تربط بين الكونترول و Designer الذي قمت بتصميمه عليك أن تستخدم DesignerAttribute Class من المهم جدا تحديد نوع Designer الذي سوف تقوم بعمل Inherits له وذلك مرتبط بك وماذا تريد. مثلا لو أردت أن تصنع Custom Control ولا تريد أن يتم إضافة أي كونترول أخري إليه أي لا تريد إضافة Child Control إليه عليك أن تستخدم ControlDesigner Class أما إذا كنت تريد أن تضيف كونترول أخري الي ما تصمم عليك أن تستخدم ParentControlDesigner Class ولتوضيح هذه النقطة لنفرض انك تريد أن تصنع Custom Control وأيضا لا تريد من المستخدم أن يقوم بإضافة عناصر أخري Child Control الي هذا الكونترول هنا عليك أن تستخدم ControlDesigner Class وطبعا العكس صحيح إذا أردت أن تضيف عناصر أخري الي الكونترول عليك هنا أن تستخدم ParentControlDesigner Class أو أي كلاس أخر مشتق منه ببساطه أكثر أن أي كونترول تقوم ببنائه وتستخدم معه ControlDesigner Class لا يمكن استخدامه كوعاء أو حاويه Container لأي أنواع أخري من الكونترول. الفرق بين ControlDesigner Class و ParentControlDesigner Class لو نظرنا الي كل من هذين الكلاسين من خلال Help File الخاص بالفيجوال استوديو سنجد أن ParentControlDesigner مشتق من ControlDesigner ولو عقدنا مقارنة بينهم سنجد أيضا أن ParentControlDesigner يمتلك عدة طرق أكثر قليلا من ControlDesigner وعددها سبعة طرق وبالمثل سبعة صفات إضافية أخري وهي موضحه كالأتي الطرق Methods AddPaddingSnapLines CanParent CreateTool CreateToolCore GetControl GetParentForComponent GetUpdatedRect الصفات Properties AllowControlLasso AllowGenericDragBox AllowSetChildIndexOnDrop DefaultControlLocation DrawGrid GridSize MouseDragTool لرؤية باق الصفات والخواص والحقول يمكنك عزيزي القاري أن تراجع ملف Help الخاص بالفيجوال استوديو كما يمكنك أيضا ن تقارن بينهم لتري الفرق بنفسك وستجد أيضا أن هناك حقل Filed كان موجودا في ControlDesigner ولكنه لم يعد موجودا في ParentControlDesigner وهذا الحقل يطلق عليه InvalidPoint مما سبق نكتشف أن الطرق والصفات التي تم إضافتها الي ParentControlDesigner هي التي خلقت الفرق بينهم وهي التي أعطت الإمكانيات لهذا Designer لكي يعطي إمكانية إضافة أي كونترول أخر الي أي Custom Control وبما أن معظم Designers مشتقه من ParentControlDesigner لذلك سوف نتحدث عنه تحديدا ونحاول أن نغطي الأجزاء الهامة به والتي نحتاجها في تصميم كونترول جديد وبمواصفات وشكل جديد. هيا نصمم Custom Control لنفتح مشروع جديد Form Application ثم نضيف له كلاس نطلق عليه MyControl و نضيف له كونترول عن طريق Inherits و أيضا في نهاية هذا الكلاس نضيف كلاس ونطلق عليه MyDesigner ونضيف أيضا له ParentControlDesigner عن طريق Inherits الأن لنربط بين الكونترول و Designer لكي نربط بين الكلاسين سوف نستخدم DesignerAttribute Class ومن ثم علينا أن نضيف Attribute الي MyControl Class والهدف هنا هو أننا نقول للكونترول MyControl أن Designer المسئول عنك هو MyDesigner ويتم إضافة DesignerAttribute (<Designer(GetType(MyDesigner))> _) مباشرة قبل MyControl Class وبذلك يكون الكود كالأتي كود : Imports System.ComponentModelتطوير الكونترول Designers الجزء الرابع - RaggiTech - 03-10-12 كيف نقوم بإضافة تعديلات الي Custom Designer لكي نقوم بذلك نحتاج أن نتحدث قليلا عن ParentControlDesigner إن الحديث عن ParentControlDesigner Class سوف يغطي بالتبعية الحديث عن ControlDesigner Class ولقد أوضحنا الفرق بينهم وأنهم لا يختلفان علي الإطلاق إلا في أشياء قليله وعموما ParentControlDesigner Class له صفات Properties و طرق Methods أكثر من ControlDesigner Class لذلك سيكون هو هدفنا هنا في هذا الجزء من تطوير الكونترول. ملحوظه هامه هناك بعض الصفات التي تخص ParentControlDesigner لا نحتاج الي التغيير في قيمها ألأوليه لان الأمر حينئذ سيكون عبارة عن مضيعة للوقت لكن بما أن الهدف هنا هو توضيح وشرح ParentControlDesigner فلسوف أحاول أن إعطاء فكره عن معظم الصفات التي تخص ParentControlDesigner والتي تهمنا في تصميم Custom Control AllowControlLasso Property هذه الصفة لها قيمه عبارة عن Boolean أي True أو False وهي خاصية يتم استدعاؤها بعد أن نضيف عنصر ما من Toolbox وتقوم برسم ReversibleRectangle ومن الأفضل عدم التعديل فيها واستخدام قيمتها الافتراضية لكن لو أراد القارئ أن يقوم بتعديلها فكل ما عليه أن يري الكود المرفق. وأيضا لمزيد من المعلومات عن ReversibleRectangle يمكنك أن تراجع كلاس مهم جدا وهو ControlPaint Class وهناك مقال قمت بنشره بالموقع تحت عنوان الكلاس التائه عن هذا الموضوع يمكن أن ترجع إليه إن أردت AllowGenericDragBox Property هذه الصفة لها قيمه عبارة عن Boolean أي True أو False وهي تحدد هل يتم رسم Drag Box عندما نحاول أن نقوم بعمل Dragging لآي عنصر من Toolbox والقيمة الافتراضية لها True ومن الأفضل عدم التعديل بها لكن لو أراد القارئ أن يقوم بتعديلها فكل ما عليه أن يري الكود المرفق. ِAllowSetChildIndexOnDrop Property هذه الصفة الغرض منها هو الحفاظ علي z-Oorder لكل الكونترول التي يتم سحبها وإضافتها Toolbox و z-Order عبارة عن visual layering للكونترول Control التي تضاف الي Custom Control وقيمة هذه الصفة عبارة عن Boolean أي True أو False وعموما القيم الافتراضية لها عبارة عن True ومن الأفضل عدم التعديل فيها واستخدام قيمتها الافتراضية لكن لو أراد القارئ أن يقوم بتعديلها أن يري الكود المرفق. DrawGrid Property واضح جدا أن هذه الصفة تسمح برسم Grid داخل Custom Control وهي عبارة عن Boolean أي True أو False والقيمة الافتراضية لها False ولو أردت أن تظهر Grid انظر الي الكود المرفق. DefaultControlLocation Property هذه الصفة الهدف منها شئ هام جدا فهي المسئولة عن تحديد النقطة Point الافتراضية أو الأولية أو مكان ChildControl داخل الكونترول أي عندما نقوم بعمل Double-Click لكي نضيف أي كونترول من Toolbox الي داخل الكونترول الخاص بنا. مثال علي ذلك عندما تقوم باستخدام الماوس والضغط علي أي كونترول عن طريق Double-Click وإضافة Button مثلا من Toolbox الي أي كونترول أو حتى الي الفورم سنجد أن المكان سيقع داخل الفورم في منطقه معينه وهذه الصفة التي نتحدث عنها هي المسئولة عن ذلك. إذن لكي نحدد المكان الذي سيقع فيه أي كونترول داخل الكونترول الذي نصممه علينا أن نقوم بعمل Overrides لهذه الخاصية و مثال غلي ذلك انظر الي الكود المرفق. GridSize Property من الواضح الهدف من الصفة فهي تحدد مقاس Grid وهي مرتبطة بالصفة DrawGrid واقل قيمه افتراضية 2 واكبر قيمة افتراضية 200 لكن لو أراد القارئ أن يقوم بتعديلها فكل ما عليه أن يري الكود المرفق. MouseDragTool Property هذه الصفة تستخدم لإضافة ToolBoxItem أثناء عملية السحب والإفلات الي Designer وهي مرتبطة بكلاس أخر وهوToolBoxItem Class وهذا الكلاس مرتبط نشئ أخر مهم و هو System.Drawing.Design Namespace. الكود المرفق.يوضح كيفية استخدام هذه الصفة الأن نقوم بعمل Build للكونترول وسوف نراه موجودا داخل Toolbox لنقوم بإضافته الي الفورم باستخدام Double Click نقوم بإضافة Button إلي الكونترول سنلاحظ أن مقاس الكونترول Size صغير إذن نحن نحتاج الي تحديد Size جديد وأيضا لو وقفنا بالماوس علي الباتون الذي أضفناه الي الكونترول ونظرنا الي صفاته المختلفة داخل Properties Window سنجد أن Button.Location أصبح (20, 20). هناك ملحوظه هامه جدا ذكرتها مايكروسوفت بخصوص التعديل في Size Property وهي للحصول علي أداء أفضل للكونترول يجب أن نقوم بتعديل خاصية Size عن طريق عمل Overrides لخاصية DefaultSize Property وليس عن طريق Constructor أي (Public Sub New) لنتوقف هنا قليلا لنستعرض الكود الي يغطي كيفية استخدام هذه الصفات السابقة كود : Imports System.ComponentModelتطوير الكونترول Designers الجزء الرابع - RaggiTech - 03-10-12 الأنواع الأخرى من الصفات 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ماذا تعني هذه الصفة؟ لأوضح أهمية الصفة سوف أعطي مثالا سريعا عندما نضيف الي الفورم أي كونترول أخر مثل 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.DesignerVerbCollectionPostFilterProperties هل فكرت يوما أن تقوم بإلغاء أو تعديل بعض الصفات الموجودة مع الكونترول أعتقد إن بعض القراء فكروا في الأمر عموما هذا ممكن عن طريق عمل Overrides الي PostFilterProperties Sub لكن من الأفضل أن لا نلغي أي صفة Property من صفات الكونترول لأن بعض الصفات مرتبطة مع بعضها البعض عن طريق Attribute ولكن أنصحك أن تقوم بعمل Override من داخل الكونترول الذي تقوم بتصميمه مع ضبط خاصية BrowsableAttribute الي False وبذلك تضرب عصفورين بحجر أي نستفيد بأن الصفة مازالت موجودة وبالتالي ممكن للمبرمج استخدامها في أي وقت يشاء من داخل الكود فقط مع أيضا إمكانية عدم ظهورها للمستخدم في مرحلة Design وبشكل عام لو أردت عزيزي القارئ أن تقوم بإلغاء بعض الصفات نهائيا فإن ذلك يتم طبقا للكود التالي كود : Protected Overrides Sub PostFilterProperties(ByVal Properties As IDictionary)هذا Sub يستخدم في إضافة صفات الي الكونترول لكي يتم استخدامها في مرحلة التصميم فقط وهي مرتبطة بخاصية أخري يمكننا من خلالها من الرسم في الكونترول في مرحلة التصميم فقط وهي OnPaintAdornments والكود التالي يوضح الأمر. كود : Private MyDesignColor As Color = Color.Blueهذا Sub يستخدم في رسم أي شئ داخل الكونترول وهو في مرحلة Design وعند التشغيل تختفي هذه الرسومات التي هي أحيانا مجرد تحديد لأبعاد الكونترول الخارجية مثلا ممكن نلاقي مرسوم Rectangle حول الكونترول وعند اختيار الكونترول فإن اللون المرسوم به المستطيل يكون في حالة Active وعندما نترك الكونترول ونختار أي كونترول أخر موجود داخل الفورم مثلا فان هذا المربع يتحول لونه الي حالة Inactive ومع ذلك مازلنا نراه في الفورم وأيضا عند التشغيل للمشروع يختفي ه1ا المربع ولا نراه إذن الأمر واضح هذا Sub يقوم برسم أي شئ داخل الكونترول ولمن يعرف كيفية التعامل مع GDI+ فإن هذا Sub يشبه تماما Form_Paint مثلا أو Panel_Paint إذن فهو يؤدي نفس الوظيفة مع الكونترول ولكن في مرحلة Design فقط وبالتالي عند استخدام هذا Sub يجب علينا أن نتعامل مع حركة الماوس أيضا مثل OnMouseEnter و OnMouseLeave وهكذا يعني ببساطه هذا Sub يتيح لنا أن نزين ونجمل ونضيف ديكور للكونترول حتى وهو في مرحلة التصميم مع الوضع في الاعتبار أن كل ما سوف يرسم سوف يختفي تماما عند التشغيل ويظهر فقط في مرحلة التصميم المثال التالي يوضح كيفية التعامل مع الامر طبعا تستطيع عزيزي القارئ أن ترسم ما تريد طبقا لمتطلباتك وخيالك. ومن عنده فكره جيده عن GDI+ يستطيع أن يبدع في هذا الأمر لكني أنصحك عزيزي القارئ أن تجعل الرسم في مرحلة التصميم بسيط جدا بقدر الإمكان حثي لا تشتت المبرمج الذي سوف يستخدم الكونترول الخاص بك. كود : Private mousemotion As Boolean = Falseتبقي شئ أخير وهذا الأمر تركته للنهاية لأهميته القصوى وأنا أتصور أن الكثير منكم لا يعلمون عنه شيئا لأن لا أحد يتحدث عنه مطلقا ولكي تجد بيانات عنه يجب أن تعرفه أولا وطبعا إذا كنت تجهله عزيزي القارئ فكيف ستبحث عنه. كل المبرمجين يعلمون ما هو ClientRectangle Area وأيضا NonClientRectangle Area السؤال الأن كيف نحدد ذلك في الكونترول الذي نقوم بتصميمه؟ هذا السؤال ربما دار بعقل الكثيرين والشيء الغريب أن لا حدا يتحدث عنه علي الإطلاق وحتى لو قمت بالبحث سوف تجد إجابات غير واضحة تماما ولربما تجعلك هذه الإجابات تدخل في متاهة كبري وتؤدي بك الي أبواب مسدودة. أكرر السؤال كيف نحدد المنطقة التي تسمي بمنطقة NonClientRectangle ؟ الإجابة علي هذا السؤال بسيطة جدا ولربما تجعلك عزيزي القارئ تفعل كما فعل أرشميدس يوما وخرج عاريا وهو يقول وجدتها Eureka . الإجابة تكمن في كلمة واحدة وهي :الأتي DisplayRectangle وهذه خاصية Read-Only Property من خواص Control Class وبما أن كل شئ مشتق من الكونترول حتى الفورم مشتق من الكونترول و لكي نقوم بالتغيير في هذه Property من الأفضل أن نربطها بصفة أخري وهي ClientRectangle Property والمثال التالي يوضح كيف نقوم بعمل Overrides لهذه الصفة. كود : Public Overrides ReadOnly Property DisplayRectangle() As Rectangleلكي تستطيع التطوير ولكي تكون Developer ناجحا عليك بالأتي:- إبحث في أصل كل كلاس تقابله وستكتشف أن من السهل أن تكتب أي كلاس وسوف نوضح ذلك في الجزء القادم من سلسلة مقالات تطوير الكونترول الذي سوف يغطي VisualStyleRenderer Class. استخدم الكونترول الموجودة ولا تحاول أن تبني الكونترول من الصفر وإلا ستحتاج لكتابة الكثير والكثير من الكود. تعلم GDI+ وتعلم أن تتقنها جيدا فهي المسئولة عن كيفية الرسم داخل أي كونترول. اتمني ان يكون الموضوع واضح وبخصوص المثال الذي وعدت به قسوق اضعه اليوم او غدا بالمنتدي بالتوفيق اخوكم عمر |