![]() |
|
WPF الأساسيات : الأحداث المُوجهّة Routed Events - نسخة قابلة للطباعة +- منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب (http://vb4arb.com/vb) +-- قسم : قسم لغات البرمجة الاخرى (http://vb4arb.com/vb/forumdisplay.php?fid=4) +--- قسم : قسم البرمجة بتقنية WPF (http://vb4arb.com/vb/forumdisplay.php?fid=86) +--- الموضوع : WPF الأساسيات : الأحداث المُوجهّة Routed Events (/showthread.php?tid=4139) |
WPF الأساسيات : الأحداث المُوجهّة Routed Events - Islam Ibrahim - 17-09-12 تم الإشارة في مقال سابق, إلى أن WPF أضاف نوعًا جديدًا من الخصائص (خصائص التبعيّة Dependency Properties), هذا النوع قام بتوسيع مفهوم خصائص CLR الكلاسيكية والمعروفة بـ CLR Properties, من جهة أخرى أضاف WPF أيضًا نوعًا جديدًا من الأحداث Events, هذا النوع الجديد هو الآخر قام بتوسيع مفهوم الأحداث الكلاسيكية , هذا النوع من الأحداث يُسمّى Routed Events, أو الأحداث المُوجهّة. تُوضِّح هذه المقالة كيفية إنشاء Routed Events واستخددامها عمليًا, محتويات هذه المقالة كالتالي:
مفهوم الأحداث قديم ومألوف لدي المُطورّين, والذي يعتمد على إرسال رسائل من كائن ما (عنصر Button على سبيل المثال), والتي تدل على وقوع حدث مُميّز. تمّ تصميم الأحداث المُوجهّة من أجل العمل بشكل متكامل مع شجرة العناصر Elements Tree في WPF, عندما يتمّ إطلاق حدث مُوجّه, يُمكنه التنقل عبر شجرة العناصر إلى أعلى أو إلى أسفل, بحيث من المُمكن أن يتم إعادة إطلاقه مرة أخرى من أجل كل عنصر من عناصر تلك الشجرة بطريقة استثنائية دون الحاجة لكتابة شفرات مُخصّصة لذلك. تعتبر الأحداث المُوجهة أحد أهم أسباب نجاح نموذج عناصر WPF, والسبب في ذلك, هو تكامل وظائفها خصوصًا عند التعامل مع تنسيقات المظهر Styles, كما أنها تسمح بكتابة شفرات أقل وأكثر تناسقًا. توجيه الأحداث يُمكِّن حدثًا ما من أن يصدر من عنصر مُحدّد, ويتم إطلاقه في عنصر آخر, على سبيل المثال, عند النقر على Button في أداة Toolbar فإن الحدث Click يتم إطلاقه انطلاقًا من ذلك الـ Button, ثمّ من أداة Toolbar, ثمّ من الإطار Window , وذلك قبل أن تتمّ مُعالجته من خلال شفراتك! كيف يُمكن كتابة الأحداث المُوجهّة؟ كيفية تعريف الأحداث المُوجهّة شبيهة إلى حد كبير بكيفية تعريف خصائص التبعيّة Dependency Properties, وكما يحدث غالبًا مع خصائص التبعيّة, فإن الأحداث المُوجهّة يتم إنشاؤها بالاستعانة بحقول مشتركة Static fields يتم تسجيلها في مُنشئ مثشترك Static constructor , ثم يتمّ تغليفها باستخدام الأحداث الكلاسيكية, والمثال التالي المأخوذ من تعريف الفئة ButtonBase يُوضِّح ذلك: PHP كود : public abstract class ButtonBase : ContentControl, ... { // تعريف الحدث public static readonly RoutedEvent ClickEvent; // تسجيل الحدث static ButtonBase() { ButtonBase.ClickEvent = EventManager.RegisterRoutedEvent( "Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase)); ... } // التغليف باستخدام الأحداث الكلاسيكية public event RoutedEventHandler Click { add { base.AddHandler(ButtonBase.ClickEvent, value); } remove { base.RemoveHandler(ButtonBase.ClickEvent, value); } } ... } عادةُ ما يتمّ تغليف الأحداث المُوجهّة باستخدام الأحداث الكلاسيكية, وذلك حتى يسهُل للغات البرمجة الوصول إليها, عند تغليف الأحداث المُوجهّة يتمّ استخدام الإجرائين AddHandler و RemoveHandler , والذين يقومان بتسجيل Subscribing أو إلغاء تسجيل Unsubscribing لمُتلقيي الأحداث Callers, كلا الإجرائين السابقين موروثان من النوع FrameworkElement الذي ترث منه جميع عناصر WPF. بالتأكيد, مثل أي حدث آخر, تحتاج لإطلاق الحدث الذي أنشأته من خلال الفئة التي قمت فيها بتعريف ذلك الحدث, ولكن بطريقة تختلف عن الطريقة الكلاسيكية التي تعوّدت عليها عند تعريف الأحداث الكلاسيكية, في WPF تحتاج لاستدعاء الإجراء RaiseEvent الموروث من النوع UIElement, والمثال التالي المأخوذ من أحد أجزاء تعريف الفئة ButtonBase يُوضّح كيفية استخدام هذا الإجراء: PHP كود : RoutedEventArgs e = new RoutedEventArgs(ButtonBase.ClickEvent, this);base.RaiseEvent(e); PHP كود : btnClick.Click += delegate { ... }; PHP كود : private void btn_MouseUp(object sender, MouseButtonEventArgs e){ } أساليب التوجيه Routing Strategies العديد من عناصر WPF عبارة عن Content Controls, ما يعني أنّ لديها القدرة على احتواء أي عدد وأي نوع من العناصر المتداخلة, على سبيل المثال, يُمكنك بناء Button باستخدام Shapes, أو إنشاء Label يحتوي على مزيج من النصوص والصُّور, ويُمكنك حتى إنشاء عناصر مُتداخلة فيما بينها لعمق غير محدود! ولكن هذا التداخل قد يثير تساؤُلاً مُثيرًا للاهتمام, افترض أن لديك عنصر Label كما في المثال التالي, والذي يحتوي على StackPanel يحمل هو الآخر عنصري TextBlock وعنصر Image : PHP كود : <Label BorderBrush="Black" BorderThickness="1"> <StackPanel> <TextBlock Margin="3"> Image and text label </TextBlock> <Image Source="happyface.jpg" Stretch="None" /> <TextBlock Margin="3"> Courtesy of the StackPanel </TextBlock> </StackPanel> </Label> ربما قد يخطر ببالك أنه يجب عليك أن تقوم بمعالجة هذا الحدث من أجل كلّ عنصر موجود داخل عنصر Label السابق, ولكن بهذه الطريقة, ستصبح شفرات Xaml أكثر تعقيدًا, وأصعب فهمًا, لهذا من المُفيد الاعتماد على الأحداث المُوجهّة في WPF التي حلّت هذه المُشكلة, توجيه الأحداث يعتمد على 3 أساليب في إطلاق الأحداث ومُعالجتها:
في الواقع ليس هناك ما يُجبرك على مُعالجة الأحداث من النوع Bubbling مرّة واحدة فقط ومن أجل عنصر واحد, ولكن هذا من الأساليب الجيّدة دائمًا حتى تُقلّل من كميّة الشفرات اللزمة لذلك, وحتى تقوم أيضًا بمُعالجة الحدث المناسب وتختار من أجل ذلك العنصر الأقرب والأكثر ملائمةً! الفئة RoutedEventArgs عندما تُعالج حدثًا من النوع Bubbling, فإن الوسيط sender سيُشير إلى آخر عنصر وصل إليه الحدث, على سبيل المثال, عندما تُعالج حدثًا يصدر من العنصر Image (المثال السابق) نحو العنصر Label, فإن الوسيط sender سيُشير للعنصر Label. وفي بعض الحالات قد تحتاج إلى تحديد المَصدر الحقيقي للحدث, في هذه الحالة يُمكنك الحصول على تلك المعلومة وبعض المعلومات الإضافية من خلال الفئة RoutedEventArgs, كما أن جميع الأحداث الموجودة في عناصر WPF تعتمد على هذه الفئة أو إحدى الفئات الموروثة منها. وفيما يلي توضيح لأهم خصائص هذه الفئة ودور كلّ منها:
يُتبع ... WPF الأساسيات : الأحداث المُوجهّة Routed Events - smss - 21-09-12 ممتاز جدا جدا RE: WPF الأساسيات : الأحداث المُوجهّة Routed Events - farhat ali - 22-07-18 بارك الله فيك |