Behaviors חלק 8 – איך מממשים Drag and Drop ב MVVM ע"י שימוש ב Behaviors

14 באוגוסט 2012

תגיות: , , ,
2 תגובות


בפוסט הקודם ראינו איך נראית הדרך הנאיבית לממש Drag and Drop ב WPF.

בפוסט הנוכחי נראה איך לממש Drag and Drop ע”י Behaviors בצורה שהיא נוחה ל MVVM.

כתיבת ה Behavior

בדומה לפוסט הקודם, המטרה שלנו היא לאפשר פעולת Drag and Drop מהמלבן לכפתור:

 

image

הפעם, במקום להרשם ב CodeBehind לארוע, נעשה זאת ע”י Behavior.

ניצור Behavior חדש בשם DraggableBehavior, שאפשר לחבר על כל אלמנט שיורש מ FrameworkElement:

   1: public class DraggableBehavior : Behavior<FrameworkElement>

   2: {

   3:  

   4:  

   5: }

 

נממש את המתודה OnAttached, ובה נרשם לאירוע PreviewMouseLeftButtonDown:

   1: public class DraggableBehavior : Behavior<FrameworkElement>

   2: {

   3:     protected override void OnAttached()

   4:     {

   5:         this.AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;

   6:     }

   7:  

   8:     void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

   9:     {

  10:  

  11:     }

  12:  

  13: }

 

כל מה שנותר עכשיו לעשות הוא לאתחל את פעולת הDrag and Drop, ולשלוח מידע כלשהו:

   1: void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

   2: {

   3:  

   4:     DataObject data = new DataObject("SomeData");

   5:  

   6:     var effects = DragDrop.DoDragDrop(this.AssociatedObject, data, DragDropEffects.Move);

   7: }

 

זה לא כל כך הגיוני שה Behavior תמיד ישלח את המחרוזת “SomeData”, ולפיכך עדיף להחליף את זה בפרמטר של ה Behavior. ניצור פרופרטי חדש בשם DragData, וניצור אותו כ DependencyProperty על מנת שהוא יתמוך גם ב DataBinding:

   1: public object DragData

   2: {

   3:     get { return (object)GetValue(DragDataProperty); }

   4:     set { SetValue(DragDataProperty, value); }

   5: }

   6:  

   7: // Using a DependencyProperty as the backing store for DragData.  This enables animation, styling, binding, etc...

   8: public static readonly DependencyProperty DragDataProperty =

   9:     DependencyProperty.Register("DragData", typeof(object), typeof(DraggableBehavior), new UIPropertyMetadata(null));

 

וכל מה שנותר הוא לודא שזה המידע שנשלח בפעולת הגרירה:

   1: DataObject data = new DataObject(DragData);

 

הקוד המלא של ה Behavior נראה כך:

   1: public class DraggableBehavior : Behavior<FrameworkElement>

   2: {

   3:     protected override void OnAttached()

   4:     {

   5:         this.AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;

   6:     }

   7:  

   8:  

   9:  

  10:     public object DragData

  11:     {

  12:         get { return (object)GetValue(DragDataProperty); }

  13:         set { SetValue(DragDataProperty, value); }

  14:     }

  15:  

  16:     // Using a DependencyProperty as the backing store for DragData.  This enables animation, styling, binding, etc...

  17:     public static readonly DependencyProperty DragDataProperty =

  18:         DependencyProperty.Register("DragData", typeof(object), typeof(DraggableBehavior), new UIPropertyMetadata(null));

  19:  

  20:  

  21:  

  22:     void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

  23:     {

  24:  

  25:         DataObject data = new DataObject(DragData);

  26:  

  27:         var effects = DragDrop.DoDragDrop(this.AssociatedObject, data, DragDropEffects.Move);

  28:     }

  29:  

  30: }

שימוש ב Behavior

כאן מגיע החלק הכיפי והאלגנטי. כל מה שצריך לעשות על מנת להוסיף את ההתנהגות הזו לכל קונטרול בעולם זה פשוט להוסיף לו את ה Behavior הזה. בדוגמא שלנו, על המלבן:

   1: <Rectangle Fill="Red" Margin="229,127,34,25"  />

פשוט נוסיף את ה Behavior:

   1: <Rectangle Fill="Red" Margin="229,127,34,25"  >

   2:     <i:Interaction.Behaviors>

   3:         <local:DraggableBehavior DragData="MVVM Friendly!" />

   4:     </i:Interaction.Behaviors>

   5: </Rectangle>

וזהו.
הקונטרול עכשיו תומך ב Drag and Drop, ללא שימוש ב Code Behind!
זו הדוגמא הראשונה שבא באמת אפשר לראות את הכוח של Behaviors, ולהתחיל להבין את כמות הבעיות הגדולה שהפיצ’ר הזה יכול לפתור לנו.

הקוד המלא של החלון נראה כך:

   1: <Window x:Class="DragDropBehaviorsDemo.MainWindow"

   2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

   5:         xmlns:local="clr-namespace:DragDropBehaviorsDemo"

   6:         Title="MainWindow" Height="350" Width="525">

   7:     <Grid>

   8:  

   9:         <Rectangle Fill="Red" Margin="229,127,34,25"  >

  10:             <i:Interaction.Behaviors>

  11:                 <local:DraggableBehavior DragData="MVVM Friendly!" />

  12:             </i:Interaction.Behaviors>

  13:         </Rectangle>

  14:  

  15:         <Button AllowDrop="True" DragDrop.Drop="button1_Drop" Content="Button" Height="60" HorizontalAlignment="Left" Margin="44,48,0,0" Name="button1" VerticalAlignment="Top" Width="101" />

  16:     </Grid>

  17: </Window>

 

כשבאירוע DragDrop.Drop אנו מטפלים ב CodeBehind אבל כמובן שאין בעיה עכשיו לטפל בו ב ViewModel, בצורה הכי נקייה שיש עבור MVVM.

image

 

את הקוד המלא ניתן להוריד מכאן.

בפוסט הבא נהפוך את הדוגמא ליותר מורכבת, ונראה איך נראה Behavior מתוחכם בעולם האמיתי.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

2 תגובות

  1. Lounny23 באוגוסט 2012 ב 21:01

    This has made my day. I wish all ptosigns were this good.

    הגב
  2. Roshan25 באוגוסט 2012 ב 5:57

    This is crystal clear. Thanks for tkaing the time!

    הגב