تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
Generic Delegates & ًWindows Forms Control - Part 2
#1
السلام عليكم ورحمة الله وبركاته

الهدف
الهدف من هذا الموضوع هو مشاركة الأفكار البرمجية

مقدمة
في الموضوعات السابقة الموجودة في اللينك التالية ناقشنا سريعا كيفية إستخدام Generic Delegates وفي هذا الموضوع سوف نتطرق لبعضا من الأساليب المختلفة التي من الممكن الاستفادة منها من خلال برامجنا

Generic Delegates & ًWindows Forms Control - Part 1

Generic Delegates - Func and Action

مثال
المثال التالي مأخوذ من موقع مايكروسوفت في اللينكـــــــــ وهو يوضح كيفية نسخ مصفوفة الي مصفوفة اخري والهدف من استخدام نفس المثال هو سهولة توضحيح الفارق بين ما كتبته مايكروسوفت و بين ما نريد ان نتطرق له هنا في موضوعنا وما يهمني في مثال مايكروسوفت هو الجزء من الكودالذي يوضح كيفية استخدام Lambada مع Generic Delegates


الكود التالي يوضح شكل الكود الخاص بمايكروسوفت وهو مكتوب للإستخدام مع Console Application

PHP كود :
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
(s1s2posCopyStrings(s1s2pos
 
     copyOperation(ordinalscopiedOrdinals3)
 
     For Each ordinal As String In copiedOrdinals
         
If String.IsNullOrEmpty(ordinalThen
            Console
.WriteLine("<None>")
 
        Else
 
           Console.WriteLine(ordinal)
 
        End If      
      Next   
   End Sub

   
Private Function CopyStrings(source() As Stringtarget() As StringstartPos 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 
         target
(ctr) = String.Copy(source(ctr))
 
     Next
      Return source
.Length startPos 
   End 
Function
End Module 

أولا
لنعيد كتابة نفس الكود حتي نستطيع استخدامه مع الويندوز فورم وذلك قبل التعمق في تطويره وهنا سوف أعيد كتابة المثال ليصلح للاستخدام مع ListBox تحديدا ولتنفيذ الكود نحتاج الي فورم موجود عليه
ListBox


PHP كود :
Public Class Form1
    Private Sub Form1_Load
(sender As ObjectAs EventArgsHandles 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(s1s2posCopyStrings(s1s2pos)
 
       copyOperation(ordinalscopiedOrdinals3)

 
       For Each ordinal As String In copiedOrdinals
            If Not String
.IsNullOrEmpty(ordinalThen
                ListBox1
.Items.Add(ordinal)
 
           End If
 
       Next

    End Sub

    Private 
Function CopyStrings(source() As Stringtarget() As StringstartPos 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 
Function

End Class 

سنلاحط في الكود أن مايكروسوفت تمرر دالة و ليس روتينا الي Generic Action و هذا يؤكد ما سبق و قلته سابقا ان Generic Delegates تقبل أن نمرر لها إما دالة Function او روتين Sub

و الكود التالي هو إعادة لصياغة نفس الكود أعلاه و لكننا هنا نمرر روتين Sub

PHP كود :
Public Class Form1
    Private Sub Form1_Load
(sender As ObjectAs EventArgsHandles 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(s1s2posCopyStrings(s1s2pos)
 
       copyOperation(ordinalscopiedOrdinals3)

 
       For Each ordinal As String In copiedOrdinals
            If Not String
.IsNullOrEmpty(ordinalThen
                ListBox1
.Items.Add(ordinal)
 
           End If
 
       Next

    End Sub

    Private Sub CopyStrings
(source() As Stringtarget() As StringstartPos 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 في صورة دالة أو في صورة روتين وهل يمكن الاستغناء عن هذا كله و الإجابة ستكون بالطبع ممكن ان نفعل هذا

و الكود التالي يوضح كيفية ان نفعل هذا عن طريقة تمرير البيانات بشكل مباشر و في صورة روتين


PHP كود :
Public Class Form1
    Private Sub Form1_Load
(sender As ObjectAs EventArgsHandles 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 Stringtarget() As StringstartPos 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
(ordinalscopiedOrdinals3)

 
       For Each ordinal As String In copiedOrdinals
            If Not String
.IsNullOrEmpty(ordinalThen
                ListBox1
.Items.Add(ordinal)
 
           End If
 
       Next

    End Sub

End 
Class 

و الكود التالي يوضح كيفية ان نفعل هذا عن طريقة تمرير البيانات بشكل مباشر في صورة دالة
PHP كود :
Public Class Form1
    Private Sub Form1_Load
(sender As ObjectAs EventArgsHandles 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 Stringtarget() As StringstartPos 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(ordinalscopiedOrdinals3)

 
       For Each ordinal As String In copiedOrdinals
            If Not String
.IsNullOrEmpty(ordinalThen
                ListBox1
.Items.Add(ordinal)
 
           End If
 
       Next

    End Sub

End 
Class 


طبعا هناك كمية من الأسئلة قد يتطرق اليها ذهن أي مبرمج

 ماهي الفائدة من كل هذا ؟

أنا لست محتاجا لكتابة الكود بهذه الطريقة؟

ساستخدم الأساليب القديمة في كتابة الكود؟

العملية مش ناقصة تضييع وقت؟

العملية مش ناقصة صداع أصلا؟

الحقيقة أنا في بداية استخدامي لنفس الأسلوب في كتابة الكود حاولت أن أقنع نفسي ب أنني لا أكتب شيئا جديداولكن بعد ان أضعت يوما كاملا في دراسة الموضوع وأيضا و كلما تقدمت في دراسة الموضوع بدأت الصورة تتضح لي بشكل افضل  و اكتشفت أنني كنت مخطئا في تساؤلاتي

والحقيقة كان أهم سؤال أردت ان أسمع إجابته هو
لماذا مايكروسوفت طورت مثل هذا الاسلوب في البرمجة
هناك مثل مصري قديم يقول الحداية لايمكن أت ترمي كتاكيت او بمعني اخر لماذا مايكروسوفت قد تضيع وقتها و فلوسها في تطوير مثل هذه الاساليب

وهنا سألت نفسي اليس Generic Delegates عبارة عن EventHandler اذا من الممكن ان نستخدمها من داخل اي كلاس مثلما نفعل مع اي EventHandler و أيضا اليس علينا ان نقوم بعممل Dispse لها

ومنا أعدت كتابة وصياغة الكود أعلاه ليأخذ شكل الكلاس التالي

PHP كود :
Public Class CopyArrayAction
    Implements IDisposable

    Private copyAction 
As Action(Of String(), String(), Integer)
 
   Private disposedValue As Boolean

    Public Sub 
New(source() As Stringtarget() As StringstartPos As IntegercurrentAction 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 
الكود التالي يوضح كيفية استخدام الكلاس اعلاه من داخل الفورم

PHP كود :
Public Class Form1
    Private Sub Form1_Load
(sender As ObjectAs EventArgsHandles MyBase.Load

        Dim ordinals
() As String = {"First""Second""Third""Fourth""Fifth"}
 
       Dim copiedOrdinals(ordinals.Length 1) As String

        Using copyAction
= New CopyArrayAction(ordinalscopiedOrdinals3Sub(sourcetargetstartPos)

 
                                                                    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(sThen
                    ListBox1
.Items.Add(s)
 
               End If
 
           Next
        End Using

    End Sub

End 
Class 

طبعا من الافضل ان نكتب الدوال او الروتينيات التي سوف تقوم بكل العمل المطلوب في نسخ المصفوفات داخل الكلاس السابق نفسه أو في كلاس منفصل او علي شكل Interface و لكن لهذا حديث اخر

عموما وعلي ما اعتقد اننا قد نكتب الكود الذي يقوم بكل العمل في شكل Interface و نمرر فقط مدخلات Interface ثم في الفورم نطبق فقط الكود و نستخدم Generic Action

و ربما و الله أعلم ان تلك هي الفائدة الرئيسية او الهدف الاساسي من بناء Generic Action

لكن ومن الواضح هنا هو اننا نستطيع اطلاق حدث به روتينات او دوال تقوم بتنفيذ بعض الكود ثم وفي النهاية نستطيع التخلص من كل هذا عن طريق عمل Dispose متهيألي ان الاسلوب هذا مناسب جدا لكتابة كلاسات يسهل تنفيذها و التخلص منها بدون التأثير علي ذاكرة الكمبيوتر

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



PHP كود :
Public Class CairoPainter
    Implements IDisposable

    Private paintAction 
As Action(Of ControlGraphicsColorRectangle)
 
   Private disposed As Boolean

    Public Sub 
New(ctrl As ControlAs Graphicsclr As Colorrect As Rectangleaction As Action(Of ControlGraphicsColorRectangle))
 
       paintAction action
        paintAction
(ctrlgclrrect)
 
   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 

الكود التالي يوضح كيفية استخدام الكلاس اعلاه لرسم مستطيل علي الفورم


PHP كود :
  Protected Overrides Sub OnPaint(As PaintEventArgs)
 
       MyBase.OnPaint(e)

 
       Dim rect As Rectangle = New Rectangle(1010100100)
 
       Using New CairoPainter(Mee.GraphicsColor.BlackrectSub(ctrlgclrrDraw(ctrlgclrr))
 
           ' 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 


في المرفقات ستجدون نسخة من الكود مكتوب بنسخة الفيجوال استوديو 2015

تقبلوا تحياتي


الملفات المرفقة
.rar   Test_GenericDelegates_MicroSoft_Example.rar (الحجم : 60.57 ك ب / التحميلات : 49)
الرد }}}
تم الشكر بواسطة:



التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم