Generic Delegates & ًWindows Forms Control - Part 2
في الموضوعات السابقة الموجودة في اللينك التالية ناقشنا سريعا كيفية إستخدام
Generic Delegates
وفي هذا الموضوع سوف نتطرق لبعضا من الأساليب المختلفة التي من الممكن الاستفادة منها من خلال برامجنا
مثال
المثال التالي مأخوذ من موقع مايكروسوفت في اللينكـــــــــ وهو يوضح كيفية نسخ مصفوفة الي مصفوفة اخري والهدف من استخدام نفس المثال هو سهولة توضحيح الفارق بين ما كتبته مايكروسوفت و بين ما نريد ان نتطرق له هنا في موضوعنا وما يهمني في مثال مايكروسوفت هو الجزء من الكودالذي يوضح كيفية استخدام
المثال التالي مأخوذ من موقع مايكروسوفت في اللينكـــــــــ وهو يوضح كيفية نسخ مصفوفة الي مصفوفة اخري والهدف من استخدام نفس المثال هو سهولة توضحيح الفارق بين ما كتبته مايكروسوفت و بين ما نريد ان نتطرق له هنا في موضوعنا وما يهمني في مثال مايكروسوفت هو الجزء من الكودالذي يوضح كيفية استخدام
Lambada & Generic Delegates
الكود التالي يوضح شكل الكود الخاص بمايكروسوفت وهو مكتوب للإستخدام مع
Console Application
Public Module TestLambda
Public Sub Main()
Dim ordinals() As String = {"First", "Second", "Third", "Fourth", "Fifth"}
Dim copiedOrdinals(ordinals.Length - 1) As String
Dim copyOperation As Action(Of String(), String(), Integer) = _
Sub(s1, s2, pos) CopyStrings(s1, s2, pos)
copyOperation(ordinals, copiedOrdinals, 3)
For Each ordinal As String In copiedOrdinals
If String.IsNullOrEmpty(ordinal) Then
Console.WriteLine("" )
Else
Console.WriteLine(ordinal)
End If
Next
End Sub
Private Function CopyStrings(source() As String, target() As String, startPos As Integer) As Integer
If source.Length <> target.Length Then
Throw New IndexOutOfRangeException("The source and target arrays must have the same number of elements.")
End If
For ctr As Integer = startPos To source.Length - 1
target(ctr) = String.Copy(source(ctr))
Next
Return source.Length - startPos
End FunctionEnd Module
أولا : لنعيد كتابة نفس الكود أعلاه حتي نستطيع استخدامه مع الويندوز فورم وذلك قبل
التعمق في تطويره وهنا سوف أعيد كتابة المثال ليصلح للاستخدام مع الليست بوكس
تحديدا ولتنفيذ الكود نحتاج الي فورم موجود عليه ليست بوكس
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ordinals() As String = {"First", "Second", "Third", "Fourth", "Fifth"}
Dim copiedOrdinals(ordinals.Length - 1) As String
Dim copyOperation As Action(Of String(), String(), Integer) = Sub(s1, s2, pos) CopyStrings(s1, s2, pos)
copyOperation(ordinals, copiedOrdinals, 3)
For Each ordinal As String In copiedOrdinals
If Not String.IsNullOrEmpty(ordinal) Then
ListBox1.Items.Add(ordinal)
End If
Next
End Sub
Private Function CopyStrings(source() As String, target() As String, startPos As Integer) As Integer
If source.Length <> target.Length Then
Throw New IndexOutOfRangeException("The source and target arrays must have the same number of elements.")
End If
For ctr As Integer = startPos To source.Length - 1
target(ctr) = String.Copy(source(ctr))
Next
Return source.Length - startPos
End FunctionEnd Class
سنلاحط
في الكود أن مايكروسوفت تمرر دالة و ليس روتينا الي
Generic Action
و هذا
يؤكد ما سبق و قلته سابقا ان
Generic Delegates
تقبل أن نمرر لها إما دالة أو روتين
و الكود التالي هو إعادة لصياغة نفس الكود أعلاه و لكننا هنا نمرر روتين
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ordinals() As String = {"First", "Second", "Third", "Fourth", "Fifth"}
Dim copiedOrdinals(ordinals.Length - 1) As String
Dim copyOperation As Action(Of String(), String(), Integer) = Sub(s1, s2, pos) CopyStrings(s1, s2, pos)
copyOperation(ordinals, copiedOrdinals, 3)
For Each ordinal As String In copiedOrdinals
If Not String.IsNullOrEmpty(ordinal) Then
ListBox1.Items.Add(ordinal)
End If
Next
End Sub
Private Sub CopyStrings(source() As String, target() As String, startPos As Integer)
If source.Length <> target.Length Then
Throw New IndexOutOfRangeException("The source and target arrays must have the same number of elements.")
End If
For ctr As Integer = startPos To source.Length - 1
target(ctr) = String.Copy(source(ctr))
Next
End Sub
End Class
السؤال
الأن هل انا في حاجة الي تمرير البيانات الي
Generic Delegates
في صورة
دالة أو في صورة روتين وهل يمكن الاستغناء عن هذا كله و الإجابة ستكون
بالطبع ممكن ان نفعل هذا
و الكود التالي يوضح كيفية تمرير البيانات بشكل مباشر و في صورة روتين
و الكود التالي يوضح كيفية تمرير البيانات بشكل مباشر و في صورة روتين
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ordinals() As String = {"First", "Second", "Third", "Fourth", "Fifth"}
Dim copiedOrdinals(ordinals.Length - 1) As String
Dim copyOperation As Action(Of String(), String(), Integer) = Sub(source() As String, target() As String, startPos As Integer)
If source.Length <> target.Length Then
Throw New IndexOutOfRangeException("The source and target arrays must have the same number of elements.")
End If
For ctr As Integer = startPos To source.Length - 1
target(ctr) = String.Copy(source(ctr))
Next
End Sub
copyOperation(ordinals, copiedOrdinals, 3)
For Each ordinal As String In copiedOrdinals
If Not String.IsNullOrEmpty(ordinal) Then
ListBox1.Items.Add(ordinal)
End If
Next
End Sub
End Class
و الكود التالي يوضح كيفية تمرير البيانات بشكل مباشر في صورة دالة
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ordinals() As String = {"First", "Second", "Third", "Fourth", "Fifth"}
Dim copiedOrdinals(ordinals.Length - 1) As String
Dim copyOperation As Action(Of String(), String(), Integer) = Function(source() As String, target() As String, startPos As Integer)
If source.Length <> target.Length Then
Throw New IndexOutOfRangeException("The source and target arrays must have the same number of elements.")
End If
For ctr As Integer = startPos To source.Length - 1
target(ctr) = String.Copy(source(ctr))
Next
Return source.Length - startPos
End Function
copyOperation(ordinals, copiedOrdinals, 3)
For Each ordinal As String In copiedOrdinals
If Not String.IsNullOrEmpty(ordinal) Then
ListBox1.Items.Add(ordinal)
End If
Next
End Sub
End Class
طبعا هناك كمية من الأسئلة قد يتطرق اليها ذهن أي مبرمج
ماهي الفائدة من كل هذا ؟
أنا لست محتاجا لكتابة الكود بهذه الطريقة؟
ساستخدم الأساليب القديمة في كتابة الكود؟
العملية مش ناقصة تضييع وقت؟
العملية مش ناقصة صداع أصلا؟
الحقيقة أنا في بداية استخدامي لنفس الأسلوب في كتابة الكود حاولت أن أقنع نفسي ب أنني لا أكتب شيئا جديداولكن بعد ان أضعت يوما كاملا في دراسة الموضوع وأيضا و كلما تقدمت في دراسة الموضوع بدأت الصورة تتضح لي بشكل افضل و اكتشفت أنني كنت مخطئا في تساؤلاتي
والحقيقة كان أهم سؤال أردت ان أسمع إجابته هو
لماذا مايكروسوفت طورت مثل هذا الاسلوب في البرمجة
هناك مثل مصري قديم يقول الحداية لايمكن أت ترمي كتاكيت او بمعني اخر لماذا مايكروسوفت قد تضيع وقتها و فلوسها في تطوير مثل هذه الاساليب
وهنا سألت نفسي اليس
ماهي الفائدة من كل هذا ؟
أنا لست محتاجا لكتابة الكود بهذه الطريقة؟
ساستخدم الأساليب القديمة في كتابة الكود؟
العملية مش ناقصة تضييع وقت؟
العملية مش ناقصة صداع أصلا؟
الحقيقة أنا في بداية استخدامي لنفس الأسلوب في كتابة الكود حاولت أن أقنع نفسي ب أنني لا أكتب شيئا جديداولكن بعد ان أضعت يوما كاملا في دراسة الموضوع وأيضا و كلما تقدمت في دراسة الموضوع بدأت الصورة تتضح لي بشكل افضل و اكتشفت أنني كنت مخطئا في تساؤلاتي
والحقيقة كان أهم سؤال أردت ان أسمع إجابته هو
لماذا مايكروسوفت طورت مثل هذا الاسلوب في البرمجة
هناك مثل مصري قديم يقول الحداية لايمكن أت ترمي كتاكيت او بمعني اخر لماذا مايكروسوفت قد تضيع وقتها و فلوسها في تطوير مثل هذه الاساليب
وهنا سألت نفسي اليس
Generic Delegates
عبارة عن
EventHandler
اذا من
الممكن ان نستخدمها من داخل اي كلاس مثلما نفعل مع اي
EventHandler
و أيضا
اليس علينا ان نقوم بعممل
Dispse
لها
ومنا أعدت كتابة وصياغة الكود أعلاه ليأخذ شكل الكلاس التالي
ومنا أعدت كتابة وصياغة الكود أعلاه ليأخذ شكل الكلاس التالي
Public Class CopyArrayAction
Implements IDisposable
Private copyAction As Action(Of String(), String(), Integer)
Private disposedValue As Boolean
Public Sub New(source() As String, target() As String, startPos As Integer, currentAction As Action(Of String(), String(), Integer))
SourceArray = source
TargetArray = target
StartPosition = startPos
copyAction = currentAction
' initialize Action
copyAction(source, target, startPos)
End Sub
Public ReadOnly Property SourceArray As String()
Public ReadOnly Property TargetArray As String()
Public ReadOnly Property StartPosition As Integer
Protected Overridable Sub Dispose(disposing As Boolean)
If disposedValue Then
Return
End If
If disposing Then
If copyAction IsNot Nothing Then
copyAction(SourceArray, TargetArray, StartPosition)
copyAction = Nothing
End If
End If
disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
End Sub
End Class ' CopyArrayAction - incomplete class
الكود التالي يوضح كيفية استخدام الكلاس اعلاه من داخل الفورم
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ordinals() As String = {"First", "Second", "Third", "Fourth", "Fifth"}
Dim copiedOrdinals(ordinals.Length - 1) As String
Using copyAction= New CopyArrayAction(ordinals, copiedOrdinals, 3, Sub(source, target, startPos)
If source.Length <> target.Length Then
Throw New IndexOutOfRangeException("The source and target arrays must have the same number of elements.")
End If
For ctr As Integer = startPos To source.Length - 1
target(ctr) = String.Copy(source(ctr))
Next
End Sub)
For Each s As String In copyAction.TargetArray
If Not String.IsNullOrEmpty(s) Then
ListBox1.Items.Add(s)
End If
Next
End Using
End Sub
End Class
طبعا
من الافضل ان نكتب الدوال او الروتينيات التي سوف تقوم بكل العمل المطلوب
في نسخ المصفوفات داخل الكلاس السابق نفسه أو في كلاس منفصل او علي شكل
Interface
و لكن لهذا حديث اخر
عموما وعلي ما اعتقد اننا قد نكتب الكود الذي يقوم بكل العمل في شكل
Interface
و نمرر فقط مدخلات
Interface
ثم في الفورم نطبق فقط الكود و
نستخدم
Generic Action
و ربما و الله أعلم ان تلك هي الفائدة الرئيسية او الهدف الاساسي من بناء
Generic Action
لكن ومن الواضح هنا هو اننا نستطيع اطلاق حدث به روتينات او دوال تقوم بتنفيذ بعض الكود ثم وفي النهاية نستطيع التخلص من كل هذا عن طريق عمل
Dispose
متهيألي ان الاسلوب هذا مناسب جدا لكتابة كلاسات يسهل تنفيذها و التخلص منها بدون التأثير علي ذاكرة الكمبيوتر
اخر شئ وبما أنني من عشاق الجرافكس و الرسم كان صعب جدا أن أفوت فرصة استخدام الاسلوب الذي نناقشه في الجرافكس و الأكواد التالية توضح بعضا من هذه الأفكار
Public Class CairoPainter
Implements IDisposable
Private paintAction As Action(Of Control, Graphics, Color, Rectangle)
Private disposed As Boolean
Public Sub New(ctrl As Control, g As Graphics, clr As Color, rect As Rectangle, action As Action(Of Control, Graphics, Color, Rectangle))
paintAction = action
paintAction(ctrl, g, clr, rect)
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then
Return
End If
If disposing Then
' dispose paintAction
If paintAction IsNot Nothing Then
paintAction = Nothing
End If
End If
disposed = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
End Sub
End Class
الكود التالي يوضح كيفية استخدام الكلاس اعلاه لرسم مستطيل علي الفورم
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
Dim rect As Rectangle = New Rectangle(10, 10, 100, 100)
Using New CairoPainter(Me, e.Graphics, Color.Black, rect, Sub(ctrl, g, clr, r) Draw(ctrl, g, clr, r))
' do nothing as the generic action will take care of the paint and will disposed
End Using
Using New CairoPainter(Me, e.Graphics, Color.Black, rect, Sub(ctrl, g, clr, r)
' draw what you want here
End Sub)
' do nothing as the generic action will take care of the paint and will disposed
End Using
End Sub
Private Sub Draw(c As Control, g As Graphics, clr As Color, rect As Rectangle)
Dim sb As New SolidBrush(clr)
g.FillRectangle(sb, rect)
End Sub
Comments
Post a Comment