GHOST2010

طريقة عمل Custom Property Editor

7 ردود في هذا الموضوع

السلام عليكــم ورحمـة الله وبركاتــه ،،

هل لاحظت يوما أثناء تصفحك لخصائص أحد الأدوات من نافذة الخصائص أن بعض الخصائص يتم تغيير قيمتها بطريقة مختلفة

فمثلا إذا نظرنا إلى خاصية من نوع Color ولتكن الخاصية BackColor فعند تغيير قيمتها يظهر محرر الخاصية بهذا الشكل

post-47088-1248005808_thumb.jpg

ولو نظرنا إلى خاصية من نوع Font ولتكن الخاصية Font لوجدنا محرر الخاصية مختلف قليلا وهو عبارة عن شاشة منفصلة بهذا الشكل

post-47088-1248005909_thumb.jpg

هذا هو ما يسمى بالـTypeEditor

هذه الفئة هى التى تخبر نافذة الخصائص كيف يتم تغيير وإظهار قيمة الخصائص المختلفة

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

بسم الله نبدأ ,,

الخطوة الأولى بالتأكيد هى فتح مشروع جديد من نوع WindowsApplication

ثم

نضيف فئة جديدة وليكن اسمها MyCustomControl وهى ستكون فأر التجارب :D

الكود الخاص بها بهذا الشكل

Public Class MyCustomControl
Inherits UserControl

Private _value As Integer

Public Property Value() As Integer
Get
Return _value
End Get
Set(ByVal value As Integer)
_value = value
End Set
End Property
End Class

كما هو واضح فى الكود ,, الفئة يتم وراثتها من الفئة UserControl وقمنا بإضافة خاصية واحدة فقط هى Value من النوع Integer

الآن لو قمنا بعمل ترجمة للمشروع سنجد أن الأداة الجديدة ظهرت فى شريط الأدوات

قم بإضافتها على الفورم وانظر إلى الخاصية Value وحاول التغيير فيها

ماذا لاحظت؟؟

بالتأكيد لم يتغير شئ :D :D

سنقوم الآن بكتابة محرر جديد للخاصية Value

نريد مثلا أن يتم تغيير قيمة الخاصية باستخدام TrackBar

قم بإضافة فئة جديدة بإسم MyValueEditor

الكود المبدئى لهذه الفئة سيكون بهذا الشكل

Imports System.Drawing.Design
Imports System.Windows.Forms.Design

Public Class MyValueEditor
Inherits UITypeEditor

Dim edsvc As IWindowsFormsEditorService
Dim tb As TrackBar

End Class

قمنا أولا باستيراد مجال الأسماء Imports System.Drawing.Design وهو الذى يحتوى على الفئة التى قمنا بوراثتها وهى UITypeEditor ومجال الأسماء System.Windows.Forms.Design وهو يحتوى على الفئة IWindowsFormsEditorService وهى المسئولة عن إظهار محرر الخصائص الخاص بنا

وقمنا بتعريف متغير من نوع TrackBar والذى يمثل الأداة التى سنستخدمها كمحرر للخاصية

الآن بما أننا قمنا بالاشتقاق من الفئة UITypeEditor فأول خطوة سنقوم بها هى تغيير طريقة تحرير الخاصية عن طريق الوظيفة GetEditStyle والتى تعود بقيمة من النوع System.Drawing.Design.UITypeEditorEditStyle وهو يدعم ثلاثة أنواع للمحررات

None: استخدام الطريقة الافتراضية

DropDown: يتم إظهار سهم صغير بجوار الخاصية مثل أداة ComboBox كما هو موجود فى الخاصية BackColor

Modal: يتم تحرير الخاصية عن طريق نافذة أخرى مثل الخاصية Font

فى مثالنا هذا سنستخدم النوع الثانى DropDown

	Public Overrides Function GetEditStyle(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
Return UITypeEditorEditStyle.DropDown
End Function

الآن سنقوم بالعمل على الوظيفة EditValue والتى يتم استدعاؤها عند قيام مستخدم الأداة بمحاولة تحرير الخاصية

ستكون بهذا الشكل

Public Overrides Function EditValue(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal provider As System.IServiceProvider, ByVal value As Object) As Object
If provider IsNot Nothing Then
edsvc = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
If edsvc IsNot Nothing Then

If tb Is Nothing Then
tb = New TrackBar
With tb
.Maximum = 100
.Minimum = 0
AddHandler tb.MouseUp, AddressOf OnSelectValue
End With
End If

If value IsNot Nothing AndAlso TypeOf value Is Integer Then
tb.Value = value
End If

edsvc.DropDownControl(tb)
value = tb.Value
End If
End If
Return value
End Function

Private Sub OnSelectValue(ByVal sender As Object, ByVal e As MouseEventArgs)
edsvc.CloseDropDown()
End Sub

نقوم بتهيئة قيمة edsvc عن طريق استدعاء الوظيفة GetService التابعة للكائن provider

الكائن edsvc هو المسئول عن إظهار المحرر الخاص بنا

بعد ذلك يتم التأكد من الكائن tb إذا كان nothing نقوم بتهيئته ونضع قيم لبعض خصائصه وأخبرنا المترجم أن يقوم باستدعاء الإجراء OnSelectValue عند تنفيذ الحدث MouseUp

فى جملة الشرط التالية يتم التأكد من المعامل value وهى تحمل قيمة الخاصية الحالية ونقوم باسنادها للخاصية Value التابعة للكائن tb

بعد أن قمنا بتهيئة المحرر الخاص بنا بقى علينا أن نقوم بإظهاره وذلك عن طريق استدعاء الإجراء DropDownControl التابع للكائن edsvc

عند تنفيذ الحدث MouseUp سيتم نقل التحكم إلى الإجراء OnSelectValue وكما هو واضح من الكود أن هذا الإجراء يقوم فقط بإخفاء المحرر عن طريق إستدعاء الإجراء CloseDropDown التابع للكائن edsvc

سيتم إعادة التحكم للوظيفة EditValue مرة أخرى بعد تنفيذ هذا الحدث عند السطر

value = tb.Value

قمنا بوضع القيمة التى اختارها المستخدم عن طريقة الـTrackBar فى المعامل value الذى يتم إرساله مرة أخرى إلى نافذة الخصائص

انتهينا من أول وأبسط محرر خصائص خاص بنا

إذهب الآن إلى الفورم وحاول تغيير قيمة الخاصية Value ,, ستجد المحرر أصبح بهذا الشكل

post-47088-1248065076_thumb.jpg

ملحوظة بسيطة

الكود السابق كله لن يعمل :D :D

لا تنزعج

فقط سنعدل جزء بسيط جدا فى كود الفئة MyCustomControl

يجب أن نخبر المترجم أن محرر الخاصية Value هو MyValueEditor

سيكون الكود النهائى للأداة بهذا الشكل

Imports System.ComponentModel
Imports System.Drawing.Design

Public Class MyCustomControl
Inherits UserControl

Private _value As Integer

<Editor(GetType(MyValueEditor), GetType(UITypeEditor))> _
Public Property Value() As Integer
Get
Return _value
End Get
Set(ByVal value As Integer)
_value = value
End Set
End Property
End Class

وهذا هو الكود النهائى للمحرر

Imports System.Drawing.Design
Imports System.Windows.Forms.Design

Public Class MyValueEditor
Inherits UITypeEditor

Public Overrides Function GetEditStyle(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
Return UITypeEditorEditStyle.DropDown
End Function

Private edsvc As IWindowsFormsEditorService
Dim tb As TrackBar

Public Overrides Function EditValue(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal provider As System.IServiceProvider, ByVal value As Object) As Object
If provider IsNot Nothing Then
edsvc = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
If edsvc IsNot Nothing Then

If tb Is Nothing Then
tb = New TrackBar
With tb
.Maximum = 100
.Minimum = 0
AddHandler tb.MouseUp, AddressOf OnSelectValue
End With
End If

If value IsNot Nothing AndAlso TypeOf value Is Integer Then
tb.Value = value
End If

edsvc.DropDownControl(tb)
value = tb.Value
End If
End If
Return value
End Function

Private Sub OnSelectValue(ByVal sender As Object, ByVal e As MouseEventArgs)
edsvc.CloseDropDown()
End Sub

End Class

أتمنى أن يكون الدرس مفيدا

تم تعديل بواسطه GHOST2010
إضافة صورة المحرر الجديد
3

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

درس رائع و متميز أخي GOST2010 خصوصا و أن الدروس المخصصة لهذا النوع من التطوير قليل و لا يرتقي إلى هذا المستوى...

شكرا

[تحرير]

لا أجد الأداة التي تمكن لي من تقييم الموضوع! المهم بالنسبة لي خمس نجوم *****

تم تعديل بواسطه محمد رضى
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

شكرا أخى محمد

تقييم الموضوع موجود فى أعلى الصفحة على اليسار بجوار اسم الموضوع :D :D

قمت بالتقييم نيابة عنك :D :D

تم تعديل بواسطه GHOST2010
أصابنى الحول ,, كتبت يمين بدل يسار
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

درس مميز و جميل ينم عن علم غزير و حب نشر العلم كما قال الخ السابق

تقييمي 5 نجوم و نصف من خمسة

-1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكــم ورحمـة الله وبركاتــه ،،

استكمالا للدرس سنقوم بإضافة جزء جديد ألا وهو كيفية رسم القيمة

بمعنى أنك لو نظرت إلى الخاصية BackColor ستجد أن اللون يتم رسمه بجوار إسمه كما فى الصورة

post-47088-1248331394_thumb.jpg

هل تريد عمل ذلك فى أدواتك الخاصة؟؟

إليك الطريقة ,,

بسم الله نبدأ ,,

قم بفتح المشروع الذى أنشأناه سابقا فى أول درس

قم بإضافة هذا الكود

	Public Enum VerticalDirections
Up
Down
End Enum

Private _dir As VerticalDirections

Public Property Direction() As VerticalDirections
Get
Return _dir
End Get
Set(ByVal value As VerticalDirections)
_dir = value
End Set
End Property

قمنا بكتابة خاصية جديدة من النوع VerticalDirections والذى يحتوى على قيمتين فقط هما Up , Down

بما أن الخاصية من نوع Enum فإن المحرر الافتراضى لها سيكون على شكل ComboBox

لن نعدل عليه شئ إلا أننا سنقوم فقط برسم صورة للاتجاه المحدد

تابع معى وستفهم ما أريد أن أوصله له

من نافذة خصائص المشروع قم بفتح التبويب Resources ثم قم بإضافة صورتين واحدة باسم up والثانية باسم down

بعد هذه الخطوة بقى علينا أن نكتب محرر الخاصية

المحرر سيكون الكود المبدئى له بهذا الشكل

Imports System.Drawing.Design
Imports System.Windows.Forms.Design

Public Class DirectionEditor
Inherits UITypeEditor

End Class

أول شئ يجب أن نقوم به هو أن نخبر المترجم أنه يمكن رسم قيمة الخاصية التى سيعمل عليها المحرر

يتم ذلك من خلال الطريقة GetPaintValueSupported وهى من النوع Boolean

فى حالتنا سنجعلها تعود بالقيمة True حتى نتمكن من الرسم

	Public Overrides Function GetPaintValueSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
Return True
End Function

الآن يمكننا الرسم بكل بساطة من خلال الإجراء PaintValue

Public Overrides Sub PaintValue(ByVal e As System.Drawing.Design.PaintValueEventArgs)
MyBase.PaintValue(e)
Dim bmp As Bitmap
If CType(e.Value, MyCustomControl.VerticalDirections) = MyCustomControl.VerticalDirections.Up Then
bmp = My.Resources.up.ToBitmap
Else
bmp = My.Resources.down.ToBitmap
End If
e.Graphics.DrawImage(bmp, e.Bounds)
End Sub

قمنا بتعريف كائن من نوع Bitmap والذى سيحمل الصورة التى سنقوم برسمها

ثم نتأكد من القيمة الحالية التى سيتم رسمها إذا كانت MyCustomControl.VerticalDirections.Up

فإن الكائن سيشير إلى الصورة up وإذا كان MyCustomControl.VerticalDirections.Down

فإن الكائن سيشير إلى الصورة down

ملحوظة: قمت باستخدام الوظيفة ToBitmap لأننى قمت بإضافة أيكونات وليس صور

بعد ذلك نستدعى الإجراء DrawImage التايع للكائن e.Graphics وهو الكائن المسئول عن عملية الرسم

إنتهينا من عملية الرسم

بقى علينا أن نخبر المترجم أن هذا هو محرر الخاصية Direction

كما فعلنا فى المثال الأول

قم بكتابة الخاصية بهذا الشكل

	<Editor(GetType(DirectionEditor), GetType(UITypeEditor))> _
Public Property Direction() As VerticalDirections
Get
Return _dir
End Get
Set(ByVal value As VerticalDirections)
_dir = value
End Set
End Property

الآن قم ببناء المشروع ثم اذهب إلى الخاصية Direction وحاول تغيير قيمتها

ستظهر لك بهذا الشكل

post-47088-1248332170_thumb.jpg

--------------------------------

الكود النهائى للمحرر

Imports System.Drawing.Design
Imports System.Windows.Forms.Design

Public Class DirectionEditor
Inherits UITypeEditor

Public Overrides Function GetPaintValueSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
Return True
End Function

Public Overrides Sub PaintValue(ByVal e As System.Drawing.Design.PaintValueEventArgs)
MyBase.PaintValue(e)
Dim bmp As Bitmap
If CType(e.Value, MyCustomControl.VerticalDirections) = MyCustomControl.VerticalDirections.Up Then
bmp = My.Resources.up.ToBitmap
Else
bmp = My.Resources.down.ToBitmap
End If
e.Graphics.DrawImage(bmp, e.Bounds)
End Sub

End Class

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

شكرا أخي GHOST2010 على الإضافة القيمة...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

شكرا

شكرا شكرا شكرا شكرا شكرا شكرا شكرا

شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا

شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا

شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا

شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا شكرا

يعطيك العافيه وسلامه

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .