من المؤكد أن قارئ هذا المقال فد سمع عن أو استخدم كلمة Enum من قبل في برامجه وتقريبا جميع NameSpaces الموجودة في الدوت نت يوجد بها Enum وأيضا قلما ما يخلو أي مشروع في الدوت نت من Enum .
وفي موضوعنا هذا سوف نركز علي كيفية الإستفادة من Enums الموجودة بالدوت نت.
ماهي Enum :
كلمة Enum هي إختصار متعارف عليه لكلمة Enumerations وهي عبارة عن ثوابت يتم تعريفها بواسطة المبرمج ومن ثم يستفيد بها بشكل ما من داخل برامجه وكلمة Enumerations تعادل كلمة التعدادات في اللغة العربية وهذا مجرد ترجمة حرفية ليس إلا ولكن التعريف الحقيقي لهذه الكلمة هو أن Enumerations عبارة عن ثوابت او متغيرات يتم وضعها معا في مجموعة ويطلق عليها إسم ما والكود التالي يوضح كيفية تعريف Enumerations
كود :
Public Enum Direction
Left
Right
Up
Down
End Enum
أيضا علي سبيل المثال لا الحصر فضاء الأسماء التالية يوجد بها عدد لا بأس به من Enumerations
System.Drawing Namespace يوجد بها ContentAlignment , KnownColor, StringAlignment و غيرهم الكثير
System.Drawing.Drawing2D Namespace يوجد بها HatchStyle, SmoothingMode, DashCap و غيرهم الكثير
System.Windows.Forms Namespace يوجد بها AnchorStyles, BorderStyle, ButtonState وغيرهم الكثير
عموما جميع الأمثلة أعلاه تؤكد شئ واحد فقط أنه لايمكن بأي حال من الأحوال الإستغناء عن Enums
كيف نستفيد من Enum :
الأمثلة التالية توضح كيفية الإستفادة من Enum في برامجنا
ولكي نستفيد أكثر من الأمثلة التي سوف نعطيها سأحاول أن أبني بعض الكونترول التي من الممكن أن نستفيد منها بشكل أكثر فعالية
المثال الأول:
فضاء الأسماء System.Drawing Namespace يوجد بها Enumerations التالية
ContentAlignment
StringAlignment
الكود التالي يوضح كيفية الإستفادة من كل منهما في بناء كونترول بسيط جدا مثل Label Control ولكنه شفاف ....... ويمكن استخدامه بسهولة ...... في برامجكم
عموما لن أناقش الكود الخاص بهذا الكونترول بشكل كامل ولكن ما يهمني هنا هو أن تلاحظوا كيف تم الاستفادة من Enum في تغيير شكل الكونترول عن طريق الإستفادة من الثوابت الموجودة في كل من ContentAlignment Eum و أيضا StringAlignment Enum والجزء التالي من الكود يوضح الأمر
كود :
If Me.Text IsNot Nothing Then
Dim format As New StringFormat()
format.LineAlignment = StringAlignment.Center
format.Trimming = StringTrimming.EllipsisCharacter
Select Case Me._textAlign
Case ContentAlignment.BottomCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.MiddleCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.TopCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Near
Exit Select
End Select
Using textBrush As New SolidBrush(MyBase.ForeColor)
e.Graphics.DrawString(MyBase.Text, MyBase.Font, textBrush, borderRect, format)
End Using
End If
أيضا الكود التالي يوضح كيفية تحديد مكان المستطيل الذي يتم من خلاله رسم صورة علي الكونترول وذلك عند تغير القيم الخاصة بالمتغيرات الموجودة داخل Enum ContentAlignment
كود :
Private Function GetImageRectangle(ByVal img As Image, ByVal rect As Rectangle, ByVal align As ContentAlignment) As Rectangle
Dim imageSize As Size = img.Size
Dim x As Integer = (rect.X + 2)
Dim y As Integer = (rect.Y + 2)
If ((align And (ContentAlignment.BottomRight Or (ContentAlignment.MiddleRight Or ContentAlignment.TopRight))) <> DirectCast(0, ContentAlignment)) Then
x = (((rect.X + rect.Width) - 4) - imageSize.Width)
ElseIf ((align And (ContentAlignment.BottomCenter Or (ContentAlignment.MiddleCenter Or ContentAlignment.TopCenter))) <> DirectCast(0, ContentAlignment)) Then
x = (rect.X + ((rect.Width - imageSize.Width) / 2))
End If
If ((align And (ContentAlignment.BottomRight Or (ContentAlignment.BottomCenter Or ContentAlignment.BottomLeft))) <> DirectCast(0, ContentAlignment)) Then
y = (((rect.Y + rect.Height) - 4) - imageSize.Height)
ElseIf ((align And (ContentAlignment.TopRight Or (ContentAlignment.TopCenter Or ContentAlignment.TopLeft))) <> DirectCast(0, ContentAlignment)) Then
y = (rect.Y + 2)
Else
y = (rect.Y + ((rect.Height - imageSize.Height) / 2))
End If
Return New Rectangle(x, y, imageSize.Width, imageSize.Height)
End Function
في المرفقات ستجدون نسخة كاملة من الكود ..........................
الأكواد الموجودة بالمثال الأول يمكن الإستفادة منها أيضا في تطوير الكود الموجود في المقال الموجود تحت اللينك التالي ..........
الكود الموجود بالمرفقات بنسخة الفيجوال استوديو 2010
وفي المشاركة التالية سوف أضع الكود كاملا الخاص بالكونترول لكي يستفيد منه من لا يملكون نسخة الفيجوال 2010
أيضا في المشاركات اللاحقة سوف نناقش كيف نستفيد أكثر من Enum و بطرق أخري مختلفة ............
الكود الخاص بالكونترول TransparentLabel والموجود بالمثال رقم 1 في المشاركة السابقة لكي يستفيد منه من لا يملكون نسخة الفيجوال 2010
فقط عليكم كتابة الكود في اي من مشروعتكم ثم عمل Build للكونترول ومن ثم ستجدون منه نسخة في صندوق الأدوات ويمكنكم التعامل معه مثلما تتعاملون مع أي كونترول أخر
يتم التحكم في شفافية الكونترول من خلال Opacity Property
Private _opacity As Double = 1.0
Private _imageAlighn As ContentAlignment = ContentAlignment.MiddleCenter
Private _textAlign As ContentAlignment = ContentAlignment.TopLeft
Private _image As Image = Nothing
#End Region
#Region " Constructor "
Public Sub New()
MyBase.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
MyBase.SetStyle(ControlStyles.Opaque, False)
MyBase.SetStyle(ControlStyles.DoubleBuffer, True)
MyBase.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
MyBase.SetStyle(ControlStyles.UserPaint, True)
MyBase.SetStyle(ControlStyles.ResizeRedraw, True)
MyBase.UpdateStyles()
End Sub
#End Region
#Region " Properties "
<Browsable(True)> _
<EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always)> _
<DefaultValue(GetType(Double), "1")> _
<TypeConverter(GetType(OpacityConverter))> _
<Description("Set the opacity percentage of the control.")> _
<Category("Aero")> _
Public Property Opacity() As Double
Get
Return Me._opacity
End Get
Set(ByVal value As Double)
If value = Me._opacity Then
Return
End If
Me._opacity = value
Me.UpdateStyles()
Me.Invalidate()
End Set
End Property
<Browsable(True)> _
<EditorBrowsable(EditorBrowsableState.Always)> _
<DefaultValue(GetType(ContentAlignment), "MiddleCenter")> _
<Description("Set the position of image within the control.")> _
<Category("Aero")> _
Public Property ImageAlign As ContentAlignment
Get
Return Me._imageAlighn
End Get
Set(ByVal value As ContentAlignment)
Me._imageAlighn = value
Invalidate()
End Set
End Property
<Browsable(True)> _
<EditorBrowsable(EditorBrowsableState.Always)> _
<DefaultValue(GetType(ContentAlignment), "TopLeft")> _
<Description("Set the position of text within the control.")> _
<Category("Aero")> _
Public Property TextAlign As ContentAlignment
Get
Return Me._textAlign
End Get
Set(ByVal value As ContentAlignment)
Me._textAlign = value
Invalidate()
End Set
End Property
<Browsable(True)> _
<EditorBrowsable(EditorBrowsableState.Always)> _
<Description("Set the image of the control.")> _
<Category("Aero")> _
Public Property Image As Image
Get
Return Me._image
End Get
Set(ByVal value As Image)
Me._image = value
Invalidate()
End Set
End Property
Public Overloads Property ForeColor As Color
Get
Return MyBase.ForeColor
End Get
Set(ByVal value As Color)
MyBase.ForeColor = value
Invalidate()
End Set
End Property
<Browsable(True), EditorBrowsable(EditorBrowsableState.Always), Localizable(True)> _
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(ByVal value As String)
MyBase.Text = value
Invalidate()
End Set
End Property
#End Region
#Region " Methods "
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
InvokePaintBackground(Me, e)
Dim rect As Rectangle = MyBase.ClientRectangle
Using sb As New SolidBrush(Color.FromArgb(Me.BackColor.A * Me.Opacity, Me.BackColor))
e.Graphics.FillRectangle(sb, Me.ClientRectangle)
rect.Width -= 1
rect.Height -= 1
e.Graphics.DrawRectangle(New Pen(sb), rect)
End Using
Dim borderRect As Rectangle = MyBase.ClientRectangle
borderRect.Width -= 1
borderRect.Height -= 1
If Me.Image IsNot Nothing Then
Me.DrawImage(e.Graphics, Image, borderRect, MyBase.RtlTranslateAlignment(Me.ImageAlign))
End If
If Me.Text IsNot Nothing Then
Dim format As New StringFormat()
format.LineAlignment = StringAlignment.Center
format.Trimming = StringTrimming.EllipsisCharacter
Select Case Me._textAlign
Case ContentAlignment.BottomCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.MiddleCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.TopCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Near
Exit Select
End Select
Using textBrush As New SolidBrush(MyBase.ForeColor)
e.Graphics.DrawString(MyBase.Text, MyBase.Font, textBrush, borderRect, format)
End Using
End If
End Sub
Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim grContainer As GraphicsContainer = e.Graphics.BeginContainer()
e.Graphics.TranslateTransform(-Me.Left, -Me.Top)
Using pe As PaintEventArgs = New PaintEventArgs(e.Graphics, e.ClipRectangle)
InvokePaintBackground(Me.Parent, pe)
InvokePaint(Me.Parent, pe)
End Using
e.Graphics.ResetTransform()
e.Graphics.EndContainer(grContainer)
End Sub
Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
MyBase.OnMove(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)
Me.Invalidate()
End Sub
Private Function GetImageRectangle(ByVal img As Image, ByVal rect As Rectangle, ByVal align As ContentAlignment) As Rectangle
Dim imageSize As Size = img.Size
Dim x As Integer = (rect.X + 2)
Dim y As Integer = (rect.Y + 2)
If ((align And (ContentAlignment.BottomRight Or (ContentAlignment.MiddleRight Or ContentAlignment.TopRight))) <> DirectCast(0, ContentAlignment)) Then
x = (((rect.X + rect.Width) - 4) - imageSize.Width)
ElseIf ((align And (ContentAlignment.BottomCenter Or (ContentAlignment.MiddleCenter Or ContentAlignment.TopCenter))) <> DirectCast(0, ContentAlignment)) Then
x = (rect.X + ((rect.Width - imageSize.Width) / 2))
End If
If ((align And (ContentAlignment.BottomRight Or (ContentAlignment.BottomCenter Or ContentAlignment.BottomLeft))) <> DirectCast(0, ContentAlignment)) Then
y = (((rect.Y + rect.Height) - 4) - imageSize.Height)
ElseIf ((align And (ContentAlignment.TopRight Or (ContentAlignment.TopCenter Or ContentAlignment.TopLeft))) <> DirectCast(0, ContentAlignment)) Then
y = (rect.Y + 2)
Else
y = (rect.Y + ((rect.Height - imageSize.Height) / 2))
End If
Return New Rectangle(x, y, imageSize.Width, imageSize.Height)
End Function
Private Sub DrawImage(ByVal g As Graphics, ByVal img As Image, ByVal imageRect As Rectangle, ByVal align As ContentAlignment)
Dim r As Rectangle = Me.GetImageRectangle(img, imageRect, align)
g.DrawImage(img, r.X, r.Y, img.Width, img.Height)
End Sub
من المؤكد أن الكثير من االمبرمجين يعلمون كيفية صناعة كونترول يتم توريثه من ListBox أو ComboBox ومن ثم نضيف له الألوان المختلفة ولو بحثتم جيدا في الموقع أو علي النت بشكل عام ستجدون أفكارا كثيرة تتحدث عن هذا الأمر. عموما المثال التالي سيوضح نفس الأمر ولكن باستخدام Enum وبأسلوب مغاير للطرق المعتادة.
في الدوت نت يوجد Enum إسمه KnownColor و الكود التالي يوضح كيفية إضافته الي ComboBox واستخدامه في الحصول علي لون معين
وتتلخص الفكرة و بإختصار شديد في أننا نقوم بتعريف متغير عبارة عن Type ومن ثم نستخدم GetType ونمرر لها Enum ومن ثم نستخدم جملة For.....Each لكي نضيف المتغيرات الموجودة في أي Enum الي ComboBox وذلك باستخدام Enum.GetValues والكود التالي يوضح الفكرة و لكي تقوم بتنفيذ الكود افتح مشروع وأضف الي الفورم .... كومبوبوكس كونترول ثم اكتب الكود بالشكل التالي
كود :
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim KnonColorEnumType As Type = GetType(KnownColor)
For Each knownColorObject As Object In [Enum].GetValues(KnonColorEnumType)
If Not ComboBox1.Items.Contains(knownColorObject) Then ComboBox1.Items.Add(knownColorObject)
Next
End Sub
End Class
ويمكن إعادة كتابة الكود أعلاه بالشكل التالي ولكن مع استخدام ListBox بدلا من ComboBox
وستلاحظون هنا كيفية تمرير القيمة مباشرة بدون تعريف متغير يعبر عن Type كما بالكود أعلاه
كود :
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each knownColorObject As Object In [Enum].GetValues(GetType(KnownColor))
If Not ListBox1.Items.Contains(knownColorObject) Then ListBox1.Items.Add(knownColorObject)
Next
End Sub
End Class
الأن وبعد أن تم إضافة القيم التي تخص KnownColor Enum يتبقي كيفية استرجاع القيمة الخاصة بكل عنصر أو كل متغير داخل Enum لذلك يمكننا أن نبني دالة بسيطة جدا لتحويل كلString من عناصر KnowColor Enum الي KnownColor ويتم ذلك باستخدام Enum.Prase والكود التالي يوضح شكل الدالة
كود :
Private Function GetKnowColorString(ByVal ColorName As String, ByVal ignoreCase As Boolean) As KnownColor
Return CType([Enum].Parse(GetType(Drawing.KnownColor), ColorName, ignoreCase), Drawing.KnownColor)
End Function
ومن ثم في الحدث SelectedIndexChanged يتم استرجاع اللون واستخدامه كيفما شئنا
والكود التالي يوضح كيفية استرجاع اللون ومن ثم تغيير خلفية االفورم
كود :
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Me.BackColor = Color.FromKnownColor(GetKnowColorString(Me.ComboBox1.SelectedItem, True))
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Me.BackColor = Color.FromKnownColor(GetKnowColorString(Me.ListBox1.SelectedItem, True))
End Sub
الكود التالي يوضح الشكل النهائي للكود وبالمرفقات ستجدون نسخة من المثال
كود :
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Fill ListBox with KnowColor Enum
For Each knownColorObject As Object In [Enum].GetValues(GetType(KnownColor))
If Not ListBox1.Items.Contains(knownColorObject) Then ListBox1.Items.Add(knownColorObject)
Next
' Fill ComboBox with KnowColor Enum
Dim KnonColorEnumType As Type = GetType(KnownColor)
For Each knownColorObject As Object In [Enum].GetValues(KnonColorEnumType)
If Not ComboBox1.Items.Contains(knownColorObject) Then ComboBox1.Items.Add(knownColorObject)
Next
End Sub
Private Function GetKnowColorString(ByVal ColorName As String, ByVal ignoreCase As Boolean) As KnownColor
Return CType([Enum].Parse(GetType(Drawing.KnownColor), ColorName, ignoreCase), Drawing.KnownColor)
End Function
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Me.BackColor = Color.FromKnownColor(GetKnowColorString(Me.ComboBox1.SelectedItem, True))
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Me.BackColor = Color.FromKnownColor(GetKnowColorString(Me.ListBox1.SelectedItem, True))
End Sub
End Class
الكود الموجود بالمرفقات بنسخة الفيجوال استوديو 2010
في المشاركات اللاحقة سوف نناقش كيف نستفيد أكثر من Enum و بطرق أخري مختلفة
مثلما فعلنا في المثال الثاني يمكننا ان نضيف أي Enum الي ComboBox أو ListBox
والمثال الثالث مجرد تأكيد لنفس الفكرة المستخدمة مع المثال الثاني ولكن من ُEnum اخر وهو Hatchstyle Enum بالإضافة الي بعض Enums الأخري
والكود التالي يوضح الشكل النهائي للكود ولتنفيذ الكود أضف الي الفورم أربعة كومبوبوكس
كود :
Public Class Form1
Private align As ContentAlignment = ContentAlignment.TopLeft
Private clr As Color = Color.Empty
Private hatch As HatchStyle = Nothing
Private pType As DashStyle = DashStyle.Dash
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Fill ComboBox1 with HatchStyle Enum
For Each hatchStyleObject As Object In [Enum].GetValues(GetType(HatchStyle))
If Not ComboBox1.Items.Contains(hatchStyleObject) Then ComboBox1.Items.Add(hatchStyleObject)
Next
' Fill ComboBox2 with ContentAlignment Enum
For Each contentAlignmentObject As Object In [Enum].GetValues(GetType(ContentAlignment))
If Not ComboBox2.Items.Contains(contentAlignmentObject) Then ComboBox2.Items.Add(contentAlignmentObject)
Next
' Fill ComboBox3 with KnowColor Enum
For Each knownColorObject As Object In [Enum].GetValues(GetType(KnownColor))
If Not ComboBox3.Items.Contains(knownColorObject) Then ComboBox3.Items.Add(knownColorObject)
Next
' Fill ComboBox4 with DashStyle Enum
For Each dashStyleObject As Object In [Enum].GetValues(GetType(DashStyle))
If Not ComboBox4.Items.Contains(dashStyleObject) Then ComboBox4.Items.Add(dashStyleObject)
Next
End Sub
Private Function GetHatchStyleFromString(ByVal hatchString As String, ByVal ignoreCase As Boolean) As HatchStyle
Return CType([Enum].Parse(GetType(HatchStyle), hatchString, ignoreCase), HatchStyle)
End Function
Private Function GetContentAlinmentFromString(ByVal hatchString As String, ByVal ignoreCase As Boolean) As ContentAlignment
Return CType([Enum].Parse(GetType(ContentAlignment), hatchString, ignoreCase), ContentAlignment)
End Function
Private Function GetKnowColorString(ByVal ColorName As String, ByVal ignoreCase As Boolean) As KnownColor
Return CType([Enum].Parse(GetType(KnownColor), ColorName, ignoreCase), KnownColor)
End Function
Private Function GetDashStyleString(ByVal ColorName As String, ByVal ignoreCase As Boolean) As DashStyle
Return CType([Enum].Parse(GetType(DashStyle), ColorName, ignoreCase), DashStyle)
End Function
' Get HatchStyle value from ComboBox1
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
hatch = GetHatchStyleFromString(Me.ComboBox1.SelectedItem, True)
Invalidate()
End Sub
' Get ContentAlignment value from ComboBox2
Private Sub ComboBox2_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox2.SelectedIndexChanged
align = GetContentAlinmentFromString(Me.ComboBox2.SelectedItem, True)
Invalidate()
End Sub
' Get Color value from ComboBox3
Private Sub ComboBox3_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox3.SelectedIndexChanged
clr = Color.FromKnownColor(GetKnowColorString(Me.ComboBox3.SelectedItem, True))
Invalidate()
End Sub
' Get Pen DashStyle value from ComboBox4
Private Sub ComboBox4_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox4.SelectedIndexChanged
pType = GetDashStyleString(Me.ComboBox4.SelectedItem, True)
Invalidate()
End Sub
' Paint Something in the Form
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim TestRectangle As New Rectangle(10, 10, 200, 200)
Dim frameRect As Rectangle = TestRectangle
frameRect.X -= 4
frameRect.Y -= 4
frameRect.Width += 8
frameRect.Height += 8
Using obrush As New Drawing2D.LinearGradientBrush(frameRect, ControlPaint.Light(clr), ControlPaint.Dark(clr), Drawing2D.LinearGradientMode.Vertical)
e.Graphics.FillRectangle(obrush, frameRect)
Using framePen As New Pen(Brushes.Black)
framePen.DashStyle = pType
e.Graphics.DrawRectangle(framePen, frameRect)
End Using
End Using
Using hBrush As New Drawing2D.HatchBrush(hatch, clr)
e.Graphics.FillRectangle(hBrush, TestRectangle)
Using borderPen As New Pen(clr)
borderPen.DashStyle = pType
e.Graphics.DrawRectangle(borderPen, TestRectangle)
End Using
End Using
If Me.Text IsNot Nothing Then
Dim format As New StringFormat()
format.LineAlignment = StringAlignment.Center
format.Trimming = StringTrimming.EllipsisCharacter
Select Case align
Case ContentAlignment.BottomCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.MiddleCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.TopCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Near
Exit Select
End Select
Dim fnt As New Font("Times /new Roman", 25.0F, FontStyle.Bold)
Using sb As New SolidBrush(Color.White)
e.Graphics.DrawString(Me.Text, fnt, sb, TestRectangle, format)
End Using
End If
End Sub
End Class
الكود الموجود بالمرفقات بنسخة الفيجوال استوديو 2010
في المشاركات اللاحقة سوف نناقش كيف نستفيد أكثر من Enum و بطرق أخري مختلفة
كما تلاحظون في الأكواد اعلاه انه في كل مرة نحاول أن نقوم بتحويل المتغيرات الموجودة داخل أي Enum وهي عبارة عن Strings إلي قيمتها العادية فإننا نبني دالة لكي نسترجع القيمة وربما لاحظتم في المثال الثالث أعلاه الدوال التالية
كود :
Private Function GetHatchStyleFromString(ByVal hatchString As String, ByVal ignoreCase As Boolean) As HatchStyle
Return CType([Enum].Parse(GetType(HatchStyle), hatchString, ignoreCase), HatchStyle)
End Function
Private Function GetContentAlinmentFromString(ByVal hatchString As String, ByVal ignoreCase As Boolean) As ContentAlignment
Return CType([Enum].Parse(GetType(ContentAlignment), hatchString, ignoreCase), ContentAlignment)
End Function
Private Function GetKnowColorString(ByVal ColorName As String, ByVal ignoreCase As Boolean) As KnownColor
Return CType([Enum].Parse(GetType(KnownColor), ColorName, ignoreCase), KnownColor)
End Function
Private Function GetDashStyleString(ByVal ColorName As String, ByVal ignoreCase As Boolean) As DashStyle
Return CType([Enum].Parse(GetType(DashStyle), ColorName, ignoreCase), DashStyle)
End Function
بالتأكيد ليس منطقيا ان نكتب دالة لكل Enum علي حدة بل الأفضل أن نكتب دالة واحدة فقط نستفيد بها في استرجاع قيمة الثوابت الموجودة داخل كل Enum وبهذا نقلل من حجم الكود المكتوب.
لذلك الدالة التالية يمكن أن تحل محل اي دالة من الدوال الأربعة أعلاه بل أيضا من الممكن استخدامها مع أي Enum وكما ستلاحطون فإنه قد تم استخدام Generics لبناء الدالة ..........
كود :
Private Function StringToEnum(Of T)(ByVal value As String, ByVal ignoreCase As Boolean) As T
If [Enum].IsDefined(GetType(T), value) Then
Return CType([Enum].Parse(GetType(T), value, ignoreCase), T)
End If
Throw New ArgumentException("value is not Enum")
End Function
والكود التالي يوضح التعديلات الجديدة بالمثال الثالث وستلاحظون ان الكود اصبح اقل من الكود الموجود بالمثال الثالث
كود :
Imports System.Drawing.Drawing2D
Public Class Form1
Private align As ContentAlignment = ContentAlignment.TopLeft
Private clr As Color = Color.Empty
Private hatch As HatchStyle = Nothing
Private pType As DashStyle = DashStyle.Dash
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FillComboBoxsWithEnumData()
End Sub
Private Sub FillComboBoxsWithEnumData()
' Fill ComboBox1 with HatchStyle Enum
For Each hatchStyleObject As Object In [Enum].GetValues(GetType(HatchStyle))
If Not ComboBox1.Items.Contains(hatchStyleObject) Then ComboBox1.Items.Add(hatchStyleObject)
Next
' Fill ComboBox2 with ContentAlignment Enum
For Each contentAlignmentObject As Object In [Enum].GetValues(GetType(ContentAlignment))
If Not ComboBox2.Items.Contains(contentAlignmentObject) Then ComboBox2.Items.Add(contentAlignmentObject)
Next
' Fill ComboBox3 with KnowColor Enum
For Each knownColorObject As Object In [Enum].GetValues(GetType(KnownColor))
If Not ComboBox3.Items.Contains(knownColorObject) Then ComboBox3.Items.Add(knownColorObject)
Next
' Fill ComboBox4 with DashStyle Enum
For Each dashStyleObject As Object In [Enum].GetValues(GetType(DashStyle))
If Not ComboBox4.Items.Contains(dashStyleObject) Then ComboBox4.Items.Add(dashStyleObject)
Next
End Sub
Private Function StringToEnum(Of T)(ByVal value As String, ByVal ignoreCase As Boolean) As T
If [Enum].IsDefined(GetType(T), value) Then
Return CType([Enum].Parse(GetType(T), value, ignoreCase), T)
End If
Throw New ArgumentException("value is not Enum")
End Function
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
hatch = StringToEnum(Of HatchStyle)(Me.ComboBox1.SelectedItem.ToString, True)
Invalidate()
End Sub
Private Sub ComboBox2_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox2.SelectedIndexChanged
align = StringToEnum(Of ContentAlignment)(Me.ComboBox2.SelectedItem.ToString, False)
Invalidate()
End Sub
Private Sub ComboBox3_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox3.SelectedIndexChanged
clr = Color.FromKnownColor(StringToEnum(Of KnownColor)(Me.ComboBox3.SelectedItem.ToString, True))
Invalidate()
End Sub
Private Sub ComboBox4_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox4.SelectedIndexChanged
pType = StringToEnum(Of DashStyle)(Me.ComboBox4.SelectedItem.ToString, True)
Invalidate()
End Sub
' Paint Something in the Form
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim TestRectangle As New Rectangle(10, 10, 200, 200)
Dim frameRect As Rectangle = TestRectangle
frameRect.X -= 4
frameRect.Y -= 4
frameRect.Width += 8
frameRect.Height += 8
Using obrush As New Drawing2D.LinearGradientBrush(frameRect, ControlPaint.Light(clr), ControlPaint.Dark(clr), Drawing2D.LinearGradientMode.Vertical)
e.Graphics.FillRectangle(obrush, frameRect)
Using framePen As New Pen(Brushes.Black)
framePen.DashStyle = pType
e.Graphics.DrawRectangle(framePen, frameRect)
End Using
End Using
Using hBrush As New Drawing2D.HatchBrush(hatch, clr)
e.Graphics.FillRectangle(hBrush, TestRectangle)
Using borderPen As New Pen(clr)
borderPen.DashStyle = pType
e.Graphics.DrawRectangle(borderPen, TestRectangle)
End Using
End Using
If Me.Text IsNot Nothing Then
Dim format As New StringFormat()
format.LineAlignment = StringAlignment.Center
format.Trimming = StringTrimming.EllipsisCharacter
Select Case align
Case ContentAlignment.BottomCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.BottomRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Far
Exit Select
Case ContentAlignment.MiddleCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.MiddleRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Center
Exit Select
Case ContentAlignment.TopCenter
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopLeft
format.Alignment = StringAlignment.Near
format.LineAlignment = StringAlignment.Near
Exit Select
Case ContentAlignment.TopRight
format.Alignment = StringAlignment.Far
format.LineAlignment = StringAlignment.Near
Exit Select
End Select
Dim fnt As New Font("Times /new Roman", 25.0F, FontStyle.Bold)
Using sb As New SolidBrush(Color.White)
e.Graphics.DrawString(Me.Text, fnt, sb, TestRectangle, format)
End Using
End If
End Sub
End Class
الكود الموجود بالمرفقات بنسخة الفيجوال استوديو 2010
في المشاركات اللاحقة سوف نناقش كيف نستفيد أكثر من Enum و بطرق أخري مختلفة
اقتباس:
[TABLE="width: 100%"]
[TR]
[TD="class: alt2"]مراقبنا العزيز سيلفر أعجبني موضوعك لكن تمنيت
أن يكون الطرح أفضل لأنك لما تطرح فكرة صغيرة ويستوعبها الجميع ويبدأو بطرح
أفكار تطورها أفضل من شرح كتاب كامل ويالله من يفهم[/TD]
[/TR]
[/TABLE]
الأخ الفاضل vb_net
دعني أوضح لك الهدف من الموضوع
فكرة المقال مبنية علي تحويل أي Enum الي مجموعة من Items وهذه Items عبارة عن String ومن ثم نضيف كل String موجود داخل Enum إلي كومبوبوكس كونترول أو أي كونترول أخر يقبل النوع Items وبعد إضافة هذه Items نحتاج الي الحصول علي قيمتها الأصلية داخل Enum ولذلك نحتاج الي تحويلها من String To Enum مرة ثانية ثم أخر شئ نستفيد بها بشكل ما
ولتطبيق الفكرة راجع المثال الموجود بالمرفقات وهو بنسخة الفيجوال 2010 وإن لم تكن تمتلك نسخة 2010 يمكنك كتابة الكود الخاص بالمثال كالتالي:
ولتطبيق الكود : أضف إلي الفورم كومبوبوكس و Panel وداخل هذه Panel أضف باتون
والكود ببساطة يستخدم الخاصة Dock في تغيير وضعية الباتون داخل Panel وذلك عندما يتم إختيار اي عنصر موجود في الكومبوبوكس
كود :
Public Class Form1
Private styledock As DockStyle = DockStyle.None
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Fill ComboBox1 with HatchStyle Enum
For Each dockStyleObject As Object In [Enum].GetValues(GetType(DockStyle))
If Not ComboBox1.Items.Contains(dockStyleObject) Then ComboBox1.Items.Add(dockStyleObject)
Next
End Sub
Private Function StringToEnum(Of T)(ByVal value As String, ByVal ignoreCase As Boolean) As T
If [Enum].IsDefined(GetType(T), value) Then
Return CType([Enum].Parse(GetType(T), value, ignoreCase), T)
End If
Throw New ArgumentException("value is not Enum")
End Function
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
styledock = StringToEnum(Of DockStyle)(Me.ComboBox1.SelectedItem.ToString, True)
Me.Button1.Dock = styledock
End Sub
لكن ما دمت قد استخدمت Generics فأنا أفضل في هذه الحالة استخدام Generic TryParse Method الموجودة في الكلاس Enum ولكن تحتاج في هذه الحالة لإضافة Generic Constraint ليكون النوع T عبارة عن Value Type لأن ال Enum هي عبارة عن Value Types :
كود :
[color=#000000][COLOR=#0000bb] [/color][color=#007700]public static class [/color][COLOR=#0000bb]EnumExtensions
[/COLOR][COLOR=#007700]{
public static [/COLOR][color=#0000bb]T ToEnum[/color][color=#007700]<[/color][color=#0000bb]T[/color][color=#007700]>([/color][color=#0000bb]this string enumValue[/color][COLOR=#007700],
[/COLOR][color=#0000bb]bool ignoreCase[/color][COLOR=#007700])
[/COLOR][color=#0000bb]where T [/color][color=#007700]: [/color][COLOR=#0000bb]struct
[/COLOR][COLOR=#007700]{
[/COLOR][color=#0000bb]T value[/color][COLOR=#007700];
if ([/COLOR][color=#0000bb]Enum[/color][color=#007700].[/color][color=#0000bb]TryParse[/color][color=#007700]<[/color][color=#0000bb]T[/color][color=#007700]>([/color][color=#0000bb]enumValue[/color][color=#007700], [/color][color=#0000bb]ignoreCase[/color][color=#007700], [/color][color=#0000bb]out value[/color][COLOR=#007700]))
return [/COLOR][color=#0000bb]value[/color][COLOR=#007700];
return default([/COLOR][color=#0000bb]T[/color][COLOR=#007700]);
}
}
[/COLOR][color=#0000bb][/color][/COLOR]
ويمكن استخدامها في هذه الحالة مع أي String بالطريقة التالية , وفي حال لم تكن القيمة المدخلة صحيحة سيقوم بإرجاع القيمة الافتراضية (التي تحمل الفيمة 0 عادةً) .
لكني أعقد أنه لا يوجد فارق كبير بين اسخدام Enum.Prase و ُEnum.TryPrase فكلاهما يقوم بتحويل String الخاص بالعناصر الموجودة في Enum من قيمة أو إسم الي Object
عموما الفارق بين الدالتين ضئيل فأحدهما وهي Enum.Prase تطلق Exception في حالة إذا كانت القيم التي تم تمريرها ليست Enum أما الأخري فهي تسترجع Boolean يحدد نجاح الدالة في تحويل عناصر Enum لأنها تعتمد علي جملة Try......Catch وبالتالي فهي لا تطلق Exception في حالة تمرير قيم أخري غير Enum ويفضل استخدام TryPrase في حالة أننا لم نكن متأكدين أن القيمة التي تم تمريرها ليست Enum بشكل عام وفي كلتا الحالتين الدالة ستعود بنفس القيمة المطلوبة لأننا نمرر لها القيمة بالشكل الصحيح
علي سبيل المثال في الكود الموجود بالمشاركة رقم 7 لن يتم إطلاق Exception وتحديدا في السطر التالي من الكود
في الواقع الغرض من استخدام Generic TryParse هو اختصار الكود قدر المستطاع , وحيث أني لم أنتبه إلى أن هذه الدالة مضافة حديثًا إلى .NET 4.0 ولم تكن موجود في الإصدارات السابقة وعمليًا فهي تقوم بنفس العمل الذي كتبته في الدالة StringToEnum و لكن الغرض الآخر منها هو إرجاع Fallback value في حال كانت المدخلات خاطئة , بدل إطلاق استثناء , خصوصاً عندما تتوقع أن تحدث أخطاء في إدخالات المستخدم .
بالنسبة لمسالة التطوير أو ال Design فأعتقد أن هناك طرق أفضل من إطلاق الاستثناءات كاستخدام Processor Directives أو Conditional Attribute .
اقتباس:
[TABLE="width: 100%"]
[TR]
[TD="class: alt2"]بالنسبة لمسالة التطوير أو ال Design فأعتقد أن هناك طرق أفضل من إطلاق الاستثناءات كاستخدام Processor Directives أو Conditional Attribute [/TD]
[/TR]
[/TABLE]
أعتقد أنك تقصد Preprocessor Directives ......؟؟؟؟؟؟ متهيالي أنها تستخدم للتناسق بين لغات البرمجة وتخطي أجزاء معينة من السورس كود في حالة وجود أخطاء....