DCSIMG
אלעד כץ | Elad Katz
Sign in | Join | Help

אלעד כץ | Elad Katz

לגו של גדולים

פיתוח לחלונות 8 עם הטמל5 - איך לתמוך בעברית ובשפות מימין לשמאל (RTL) בגרסה הסופית של חלונות8

פורסם בתאריך Aug 28 2012, 10:53 PM על ידי eladkatz

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

כשמריצים אפליקציית גריד בפעם הראשונה, כך היא נראית – מיושרת לשמאל:

 

image

בשביל להפוך את השפה צריך להגדיר עברית כשפה בתוך ה application manifest, בטאב הראשון:

image

בדומה למה שהיה בגרסה הקודמת, מה שזה עושה זה מוסיף פסדו סלקטור של CSS, כך שנוכל להגדיר התהגות מיוחדת ע”י הסלקטור  -ms-lang.

הבעיה היא שאם נריץ את האפליקציה עכשיו, נראה באג מוזר. כל הקונטרולים מסוג listview מתנהגים מאוד מוזר, ומופיעים במקום הלא נכון בעמוד. זה בפירוש משהו שלא היה בגרסה הקודמת.

image

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

 

image

בתוך navigator.js ישנה פונקציה שמייצרת אלמנט דף חדש:

// Creates a container for a new page to be loaded into.
_createPageElement: function () {
    var element = document.createElement("div");
    element.style.width = "100%";
    element.style.height = "100%";
    return element;
},

כל מה שצריך לעשות בשביל לתקן את הבאג הוא להוסיף את השורה הבאה:

element.setAttribute("dir", window.getComputedStyle(this._element, null).direction);

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

 

// Creates a container for a new page to be loaded into.
_createPageElement: function () {
    var element = document.createElement("div");
 
    element.setAttribute("dir", window.getComputedStyle(this._element, null).direction);
 
    element.style.width = "100%";
    element.style.height = "100%";
    return element;
},

בהרצה נוספת נראה כי אכן כל האלמנטים זזו בחזרה למקום הנכון.

image

כל מה שנותר כעת לסדר זה ריווחים – וזה בדיוק כמו פעם שעברה. את כל ה Margin-ים צריך לתקן כך שימין יהפוך לשמאל וההפך.

כדוגמא, בקובץ default.css יש את הגדרת ה CSS הבאה.

 

.fragment header[role=banner] .win-backbutton {
    margin-left: 39px;
    margin-top: 59px;
}

במידה ואנחנו בעברית, נרצה לשנות את הגדרת ה margin-left להיות margin-right.

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

 

.fragment header[role=banner] .win-backbutton {
    margin-left: 39px;
    margin-top: 59px;
}
 
.fragment header[role=banner] .win-backbutton:-ms-lang(ar, dv, fa, he, ku-Arab, pa-Arab, prs, ps, sd-Arab, syr, ug, ur, qps-plocm) {
    margin-right: 39px;
    margin-top: 59px;
}

כך, רק בשפה מימין לשמאל הגדרת הMargin תתהפך.

כל אלמנט CSS שקיים בטמפלייט הזה צריך לעבור אותו טיפול. אחרי שנעבור על כולם ונריץ, נראה כי אכן הטמפלייט מותאם לעברית בצורה מלאה.

 

image

 

את הפרוייקט המלא ניתן להוריד מכאן
להורדת קבצי ה CSS וה JS בלבד

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

פורסם בתאריך Aug 14 2012, 06:42 PM על ידי eladkatz

בפוסט הקודם ראינו איך נראית הדרך הנאיבית לממש 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 מתוחכם בעולם האמיתי.

Behaviors חלק 7 - איך מממשים Drag and Drop ב WPF ע"י Code Behind

פורסם בתאריך Aug 14 2012, 06:42 PM על ידי eladkatz

בפוסט הקודם ראינו איך פותרים את בעיית ה Commands ב MVVM ע”י שימוש ב Behaviors. בפוסטים הבאים נתחיל לחקור הרבה בעיות ש Behaviors מפשטים, כשנתחיל עם Drag and Drop.

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

כדוגמא, ניקח את המסך הבא, בו נרצה לממש Drag and Drop מהמלבן לעבר הכפתור.

image

פעולת ה Drag and Drop תתחיל כשנמקם את סמן העכבר מעל למלבן, נלחץ על הכפתור השמאלי ונתחיל לגרור. בשביל זה צריך להרשם לאירוע MouseLeftButtonDown על המלבן:

 

   1: <Window x:Class="DragDropBehaviorsDemo.NoMvvmWindow"
   2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:         Title="NoMvvmWindow" Height="313" Width="542">
   5:     <Grid>
   6:         <Button Content="Button" Height="73" HorizontalAlignment="Left"
   7:                 Margin="31,37,0,0" Name="button1" VerticalAlignment="Top" Width="125" />
   8:         
   9:         <Rectangle Height="159" HorizontalAlignment="Left" Margin="194,88,0,0" MouseLeftButtonDown="rectangle1_MouseLeftButtonDown"
  10:                    Name="rectangle1" Stroke="Black" VerticalAlignment="Top" Width="287" Fill="#FF004CFF" />
  11:         
  12:     </Grid>
  13: </Window>

בשביל לאתחל פעולת Drag and Drop נשתמש במתודה הסטאטית DoDragDrop של במחלקת העזר DragDrop. המתודה מקבלת שלושה פרמטרים – הפרמטר הראשון הוא קונטרול המקור שפעולת הגרירה התחילה ממנו, והפרמטר השני הוא המידע אותו אנחנו רוצים להעביר לקונטרול המטרה (שבמקרה שלנו יהיה הכפתור).
הפרמטר השלישי קובע את האפקט שנראה על סמן העכבר בשעת הגרירה (אפקט העברה, אפקט העתקה וכו’) בדוגמה שלהלן אנו קובעים את המקור להיות המלבן, את המידע להיות המחרוזת “SomeData”, ואת האפקט להיות אפקט העברה (Move): image

   1: private void rectangle1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
   2: {
   3:     DataObject data = new DataObject("SomeData");
   4:  
   5:     var effects = DragDrop.DoDragDrop(sender as DependencyObject, data, DragDropEffects.Move);
   6: }

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

image

בשביל שנוכל להגיב לפעולת הגרירה, צריך לקבוע את הערך AllowDrop להיות true על כל אלמנט שעליו ניתן “להפיל” את הגרירה. במקרה שלנו זה יהיה הכפתור.
בנוסף, בשביל לטפל באירוע ה”הפלה” צריך להרשם לאירוע DragDrop.Drop:

 

   1: <Button AllowDrop="True" DragDrop.Drop="button1_Drop" Content="Button" Height="73" HorizontalAlignment="Left"
   2:         Margin="31,37,0,0" Name="button1" VerticalAlignment="Top" Width="125" />

 

האירוע חושף לנו DragEventArgs שממנו אפשר להוציא את השולח ואת המידע שהוא שלח:

   1: private void button1_Drop(object sender, DragEventArgs e)
   2: {
   3:     var data = e.Data.GetData(typeof(string)).ToString();
   4:  
   5:     MessageBox.Show(data);
   6: }

image

image_thumb[2]

וזה כל מה שצריך לעשות על מנת לממש Drag and Drop בצורה נאיבית.

ישנן שתי בעיות בשיטה הנ”ל:
1. Reuse של קוד – במידה ורוצים לממש Drag and Drop בעוד קונטרולים/חלונות, צריך להרשם לכל האירועים הרלוונטים ולכתוב את הקוד הזה פעם נוספת. רחוק מלהיות אלגנטי.

2. איך מממשים את זה ב MVVM? המחלקה DragDrop היא מחלקת UI – זו מחלקה שאסור לגשת אליה מה ViewModel. גם אם היינו ניגשים אליה מהViewModel – זו לא פעולה שה ViewModel אמור בכלל לדעת עליה היות וזו אחריות של ה View בלבד.

בפוסט הבא נראה איך ע”י שימוש ב Behaviors אפשר להגיע לפתרון הרבה יותר אלגנטי וריוזאבילי (reuseable), שמאוד נוח לשימוש ב MVVM.

Behaviors חלק 6– פתרון בעיית ה Commands ב MVVM

פורסם בתאריך Aug 10 2012, 05:47 PM על ידי eladkatz

בפוסט הקודם ראינו איך כותבים Action מאפס בעצמנו. בפוסט הנוכחי נראה את אחד השימושים הכי שימושיים ב Actions – ולמעשה איך נפתרת אחת הבעיות המציקות בשימוש ב Commands תחת MVVM.

 

בעיית ה Commands.

תחת MVVM, הדרך היחידה לחבר בין ה View לבין ה ViewModel זה על ידי Binding ו Commands. כך מתקבלת הפרדה טובה יותר מאשר הייתה לפני כן.
בגדול, המידע יעבור בין ה ViewModel ל View ע”י Binding, ופעולות יעברו מה View ל ViewModel על ידי Commands.

כדוגמא, ניצור חלון שמחובר ל ViewModel. ב ViewModel נגדיר Command בסיסי (אני משתמש ב RelayCommand מתוך MVVM Light). כך יראה ה ViewModel:

 

   1: public class MainViewModel : INotifyPropertyChanged
   2: {
   3:     public RelayCommand SomeCommand { get; set; }
   4:  
   5:     public MainViewModel()
   6:     {
   7:         SomeCommand = new RelayCommand(() =>
   8:             { 
   9:                 // Just to see that we catch the command:
  10:                 MessageBox.Show("Command caught");
  11:             });
  12:     }
  13:  
  14:     public event PropertyChangedEventHandler PropertyChanged;
  15: }

 

(כשכמובן בעולם האמיתי לעולם לא נרים MessageBox מתוך ה ViewModel).
בתוך הView נשים כפתור, שמחובר ל Command שמוגדר ב ViewModel. ה View יראה כך:

 

   1: <Window x:Class="ActionDemo.MainWindow"
   2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:         xmlns:local="clr-namespace:ActionDemo"
   5:         Title="MainWindow" Height="350" Width="525">
   6:     <Window.DataContext>
   7:         <local:MainViewModel />
   8:     </Window.DataContext>
   9:     <Grid>
  10:         <Button Content="Activate Command" Command="{Binding SomeCommand}" />
  11:     </Grid>
  12: </Window>

 

וכשנריץ – לחיצה על הכפתור אכן תרים את ה Command כפי שציפינו:

 

image

 

הבעיה היא ש Commands זה פיצ’ר טיפה מוגבל. ל Commands אפשר להרשם רק מקונטרולים שחושפים את הפרופרטי Command, שהם אך ורק קונטרולים שיורשים מ ButtonBase או MenuItem. במידה ואנו רוצים להשתמש ב Command על TextBox לדוגמא, אנחנו תקועים. יותר מזה, גם הקונטרולים שכן עובדים עם Command יודעים להרים אותו רק בלחיצה, ולא כתגובה לשום אירוע אחר. אם נרצה שה Command יופעל כתוצאה מהאירוע MouseEnter אנחנו תקועים.

 

פתרון ע”י שימוש ב Action

נוכל לפתור את הבעיה בצורה מאוד אלגנטית ע”י שימוש ב Actions.
נגדיר Action חדש בשם InvokeCommandAction: (נא לא לשכוח להוסיף רפרנס ל System.Windows.Interactivity)

 

 

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Windows.Interactivity;
   6: using System.Windows;
   7:  
   8: namespace ActionDemo
   9: {
  10:     public class InvokeCommandAction : TriggerAction<UIElement>
  11:     {
  12:         protected override void Invoke(object parameter)
  13:         {
  14:             throw new NotImplementedException();
  15:         }
  16:     }
  17: }

 

נוסיף ל Action שלנו פרופרטי מסוג Command. הרעיון הוא שכשה Action יופעל – הוא יפעיל את ה Command שניתן לו כפרמטר.
בנוסף חשוב ליצור את הפרופרטי כ DependencyProperty היות ואנו רוצים שזה יתמוך ב Binding. לפיכך נוסיף את הפרופרטי הבא:

 

   1: public ICommand Command
   2: {
   3:     get { return (ICommand)GetValue(CommandProperty); }
   4:     set { SetValue(CommandProperty, value); }
   5: }
   6:  
   7: // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
   8: public static readonly DependencyProperty CommandProperty =
   9:     DependencyProperty.Register("Command", typeof(ICommand), typeof(InvokeCommandAction), new UIPropertyMetadata(null));

 

כמעט סיימנו. כל מה שנותר לנו עכשיו הוא להפעיל את ה Command במידה וה Action מופעל. את זה נעשה בתוך המתודה Invoke:

 

   1:  
   2:         protected override void Invoke(object parameter)
   3:         {
   4:             if (Command != null)
   5:                 Command.Execute(null);
   6:         }

 

סיימנו עם ה Action – כל מה שנותר זה לחבר את ה Action שיצרנו לכפתור.
נשנה את הקוד שהיה לנו מקודם – נוריד את הרישום הרגיל ל Command, ובמקום זה נוסיף את ה Action שלנו, ונחבר את ה Action ל Command שהיה שם מקודם. עכשיו אפשר לשים את ה Action שלנו כתגובה לכל אירוע בעולם. במקרה הזה נבחר את האירוע MouseEnter:

   1: <Window x:Class="ActionDemo.MainWindow"
   2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:         xmlns:local="clr-namespace:ActionDemo"
   5:         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
   6:         Title="MainWindow" Height="350" Width="525">
   7:     <Window.DataContext>
   8:         <local:MainViewModel />
   9:     </Window.DataContext>
  10:     <Grid>
  11:         <Button Content="Activate Command" >
  12:             <i:Interaction.Triggers>
  13:                 <i:EventTrigger EventName="MouseEnter">
  14:                     <local:InvokeCommandAction Command="{Binding SomeCommand}" />
  15:                 </i:EventTrigger>
  16:             </i:Interaction.Triggers>
  17:         </Button>
  18:     </Grid>
  19: </Window>

 

בהרצת האפליקציה, נכניס את סמן העכבר מעל לכפתור ונראה שאכן ה Command הופעל כתגובה לאירוע רגיל!

 

image

 

ה Action שבנינו הוא מאוד שימושי, אם כי לא סיימנו. עקרונית כדאי להוסיף פרופרטי שני בשם CommandParameter בשביל שנוכל לשלוח גם פרמטר עם ה Command, אבל זה כבר מאוד פשוט… במקום לכתוב את זה מאפס – נשתמש במה שכבר כתוב -
ה Action שבנינו כל כך שימושי, שלמעשה הוא כבר קיים בתוך System.Windows.Interactivity – זה אחד ה Action – ים היחידים שכבר כתובים היות והוא כל כך שימושי. בשביל להשתמש בו, פשוט נחליף את ה Action שלנו ב Action מתוך מרחב השמות של ה Behaviors – i:

 

   1: <Button Content="Activate Command" >
   2:     <i:Interaction.Triggers>
   3:         <i:EventTrigger EventName="MouseEnter">
   4:             <!--<local:InvokeCommandAction Command="{Binding SomeCommand}" />-->
   5:             <i:InvokeCommandAction Command="{Binding SomeCommand}" />
   6:         </i:EventTrigger>
   7:     </i:Interaction.Triggers>
   8: </Button>

ונקבל את אותה תוצאה בדיוק.

ה Action שכתבנו בסופו של יום כבר כתוב כחלק מה Behaviors, אבל בכל זאת אפשר לראות כאן בסיס לפתרון של הרבה מאוד בעיות ב MVVM  כפי שנראה בהמשך. יתרה מזאת, כפי שנראה, Behaviors יעזרו לנו לקבל תובנה לגבי סוגים של הפרדות – הפרדה של רכיבים גנרים לעומת הפרדה של רכיבים לא גנרים בעלי אחריות ספציפית – שמהווה אבן יסוד בארכיטקטורת קליינט. אבל עד שנגיע לשם יש עוד כמה פוסטים.. Smile

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

המדריך להוספת וידאו בבלוגים - המצגת שהראיתי אתמול במפגש הבלוגרים 17.8 במיקרוסופט

פורסם בתאריך Jul 18 2012, 01:50 PM על ידי eladkatz

 

מפגש הבלוגרים אתמול היה בהחלט כיפי  – תמיד כיף להפגש עם האנשים שמאחורי הבלוגים.. ובטח עכשיו כשכולנו דוגמנים באתר הראשי Smile

להלן המצגת שהראיתי במהלך המפגש – המדריך לוידאו בבלוג:

 

Blog video guide
View more PowerPoint from Elad Katz

 

מקוה שנהניתם, ושהצלחתי להחיות את הנושא טיפה Smile

Behaviors חלק 5 - יצירת Action משלנו

פורסם בתאריך Jul 06 2012, 11:35 AM על ידי eladkatz

בפוסט הקודם ראינו איך אפשר להוסיף TriggerActions (או פשוט Actions, פעולות) ע”י בלנד. בפוסט הנוכחי נראה איך אפשר לכתוב Actions מאפס בעצמנו.

 

כמובן על מנת להתחיל נרשום את מרחב השמות של Behaviors (שימו לב כי Behaviors הוא שם כללי לשני הסוגים, גם ל Behaviors וגם ל Actions):

 

בשביל להוסיף Action, נשים על החלון מלבן, ונכין את הקרקע להוספת Action:

<Grid>
    <Rectangle Fill="#FFF4F4F5" Margin="119,87,166,103" Stroke="Black">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseUp">
 
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Rectangle>
</Grid>

במקום i:Interacgtion.Behaviors רשמנו i:Interaction.Triggers כששם אפשר להוסיף את ה Actions שלנו.
כל Action מכיל פעולה בלבד, ללא ה”מתי”. במקרה שלנו הוספנו EventTrigger שמקשיב לאירוע MouseUp. באותה מידה היינו יכולים להרשם לכל אירוע אחר של המלבן.

עד כאן הכנת השטח – נעבור ליצירת ה Action שלנו בקוד. בשביל ליצור Action צריך לרשת מ TriggerAction<T> :

public class ChangeColorTriggerAction : TriggerAction<Rectangle>
{
}

ה Action שאנו הולכים ליצור הולך “לשבת” על מלבן, ולפיכך ירשנו מ TriggerAction של Rectangle. ה Action ישנה את הצבע של המלבן (כש*מתי* זה קורה יקבע ע”י הEventTrigger שלעיל).

בשביל לממש TriggerAction כל מה שצריך זה לממש מתודה אחת – Invoke:

public class ChangeColorTriggerAction : TriggerAction<Rectangle>
{
    protected override void Invoke(object parameter)
    {
        throw new NotImplementedException();
    }
}

 

לצורך הדוגמא, נרשום בתוך invoke את הקוד הבא, שפשוט משנה את צבע המילוי של ה Rectangle לאדום.

public class ChangeColorTriggerAction : TriggerAction<Rectangle>
{
    protected override void Invoke(object parameter)
    {
        this.AssociatedObject.Fill = Brushes.Red;
    }
}

 

כעת נוכל להשתמש ב Action שלנו:

<Grid>
    <Rectangle Fill="#FFF4F4F5" Margin="119,87,166,103" Stroke="Black">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseUp">
                <my:ChangeColorTriggerAction />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Rectangle>
</Grid>

 

וכך תראה התוכנה בזמן ריצה לאחר שלחצנו על המלבן:

 

image

 

עבודה עם בלנד

במידה ונעבור לבלנד, נראה כי הAction שיצרנו נמצא שם. בלנד יודע אוטומאטית לסרוק את כל הפרוייקטים/ DLLים באפליקציה להוציא מהם את ה Behaviors וה Actions. (מאוד שימושי כשעובדים עם מעצבים גראפים) :

 

image

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

 

image

בעוד אם ננסה לגרור על האליפסה בלנד לא יאפשר לנו. (סמן העכבר גם יציין זאת, אך בצילום המסך לא רואים את הסמן):

 

image

התמיכה של בלנד ב Actions היא מלאה לחלוטין, וזה עוד אחת מהסיבות שזה פיצ’ר כזה חזק. אם נסתכל בעץ האלמנטים נראה שה Actions אכן נמצאים שם.

 

image

ואם נבחר אחד מהם נראה שאפשר לשנות פרמטרים בחלון המאפיינים. :

 

image

 

נחזור לויז’ואל סטודיו ונראה את הקוד שבלנד הוסיף – בדיוק הקוד שאנו היינו צריכים להוסיף על מנת להשתמש ב Action:

 

<Grid>
      <Rectangle Fill="#FFF4F4F5" Margin="119,87,166,103" Stroke="Black">
          <i:Interaction.Triggers>
              <i:EventTrigger EventName="MouseUp">
                  <my:ChangeColorTriggerAction />
              </i:EventTrigger>
          </i:Interaction.Triggers>
      </Rectangle>
      <Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Right" Height="88" Margin="0,39,55,0" Stroke="Black" VerticalAlignment="Top" Width="165">
          <i:Interaction.Triggers>
              <i:EventTrigger EventName="MouseLeftButtonDown">
                  <my:ChangeColorTriggerAction/>
              </i:EventTrigger>
          </i:Interaction.Triggers>
      </Rectangle>
      <Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Right" Height="106" Margin="0,0,45,30" Stroke="Black" VerticalAlignment="Bottom" Width="175"/>
  </Grid>

עקרונית, אפשר כבר להבין בשלב הזה שאין סיבה אמיתית שב Action שלנו נוכל להשתמש רק על Rectangleים – אנו נרצה שנוכל להשתמש בהם איפה שרק אפשר. איפה שרק אפשר במקרה שלנו == על כל אלמנט שיש לו מאפיין בשם Fill – או במילים אחרות, על כל מי שיורש מהמחלקה Shape (וכך נוכל לשים אותו גם על האליפסה).
נשנה את ה Action כך שיתאים לכל Shape:

 

public class ChangeColorTriggerAction : TriggerAction<Shape>
{
    protected override void Invoke(object parameter)
    {
        this.AssociatedObject.Fill = Brushes.Red;
    }
}

ועכשיו נוכל לשים אותו גם על האליפסה:

 

<Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Right" Height="106" Margin="0,0,45,30" Stroke="Black" VerticalAlignment="Bottom" Width="175">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <my:ChangeColorTriggerAction/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Ellipse>

 

image

 

הוספת DependencyProperties ל Action

אין שום סיבה שנשתמש תמיד בצבע אדום – ולכן נשנה את הקוד שלנו כך שיהיה יותר גנרי.
עקרונית, כל מה שאנו צריכים לעשות זה להוסיף מאפיין (פרופרטי) ל Action שלנו מסוג Brush על מנת שנוכל לקבוע מ”בחוץ” את הצבע אליו צריך לשנות. הפרופרטי הזה יכול להיות פרופרטי רגיל, אבל בשביל שהוא יוכל לתמוך ב DataBinding בהמשך, עדיף בהרבה שהוא יהיה פרופרטי מסוג DependencyProperty.

נוסיף DependencyProperty מסוג Brush, ונשנה אליו כאשר ה Action מופעל:

 

public class ChangeColorTriggerAction : TriggerAction<Shape>
{
    public Brush Color
    {
        get { return (Brush)GetValue(ColorProperty); }
        set { SetValue(ColorProperty, value); }
    }
 
    // Using a DependencyProperty as the backing store for Color.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ColorProperty =
        DependencyProperty.Register("Color", typeof(Brush), typeof(ChangeColorTriggerAction), new UIPropertyMetadata(Brushes.Black));
 
    protected override void Invoke(object parameter)
    {
        this.AssociatedObject.Fill = Color;
    }
}

 

מה שיאפשר לנו לרשום את הקוד הבא, והלהשתמש כל פעם בצבע אחר:

 

<Grid>
        <Rectangle Fill="#FFF4F4F5" Margin="119,87,166,103" Stroke="Black">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseUp">
                    <my:ChangeColorTriggerAction Color="Blue" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Rectangle>
        <Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Right" Height="88" Margin="0,39,55,0" Stroke="Black" VerticalAlignment="Top" Width="165">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonDown">
                    <my:ChangeColorTriggerAction Color="Green"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Rectangle>
        <Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Right" Height="106" Margin="0,0,45,30" Stroke="Black" VerticalAlignment="Bottom" Width="175">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseEnter">
                    <my:ChangeColorTriggerAction Color="Yellow"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Ellipse>
    </Grid>

 

וזו התוצאה הסופית שנקבל

 

image

 

בפוסט הבא נכתוב את ה Action הראשון הבאמת שימושי – Action שאי אפשר לעבוד בלעדיו כשעובדים ב MVVM.

Behaviors חלק 4 - שימוש ב TriggerActions

פורסם בתאריך Jul 06 2012, 10:57 AM על ידי eladkatz

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

התנהגויות באות למעשה בשני סוגים, כשלשניהם קוראים בשם הכללי Behaviors: ה Behaviors שראינו עד עכשיו, ו TriggerActions שמספק טיפה יותר שליטה על *מתי* הפעולה מופעלת. למעשה Behavior מוסיף התנהגות שלמה שפשוט מוסיפים על אלמנטים בזאמל, בעוד Actions מאפשרים לנו להפעיל פעולה מסוימת, כשאנו יכולים לקבוע מתי הפעולה הזו תקרה – כתגובה לאיזה אירוע.

איך מוסיפים Action?

 

בפוסט הבא נראה איך יוצרים TriggerAction משלנו מאפס.

קוד ומצגת ליום הפתוח שהתקיים ב 25.6 במיקרוסופט - פיתוח לחלונות 8 ב HTML5

פורסם בתאריך Jun 26 2012, 06:56 PM על ידי eladkatz

תודה לכל מי שהגיע ליום הפתוח שהתקיים אתמול (25.6) במיקרוסופט רעננה.

להלן המצגת שהראיתי במהלך ההרצאה: (שימו לב שבהרצאה לא הספקנו לעבור על הכל)

 

ואת הקוד ניתן להוריד מכאן: http://sdrv.ms/Qc21TU

את בלנד, הכלי שהדגמתי בסוף אפשר להוריד כחלק מויז’ואל סטודיו 2012 (שימו לב כי למרות שויז’ואל סטודיו 2012 עובד גם על חלונות 7, אפשר לפתח לחלונות 8 רק תחת חלונות 8.

פורום חדש ב MSDN ישראל לאפליקציות מטרו של חלונות 8

פורסם בתאריך Jun 20 2012, 09:53 PM על ידי eladkatz

פורום חדש נפתח ב MSDN ישראל – פורום לאפליקציות מטרו של חלונות 8 (http://bit.ly/metro-il)

הפורום הינו פורום יעודי לאפליקציות מטרו, בין אם זה ב XAML ובין אם זה ב HTML.
את הפורום ינהלו אלעד שחם, ארכיטקט בקבוצת סלע, תומר שמם, ואנוכי. (בין כולנו תהיה תמיכה לכל סוגי האפליקציות)

חלונות 8 הגיע לגרסת RP ממש לאחרונה, ואם עדיין לא התחלתם לפתח למערכת החדשה, עכשיו זה הזמן להתחיל. ההייפ סביב מערכת ההפעלה החדשה עולה כל הזמן (ודי בצדק), כשרק בימים האחרונים הוכרז מחשב טבלט יעודי של מיקרוסופט לחלונות 8 – Surface, והיום הוכרז שחלונות לטלפון 8 (WP8) מבוסס גם הוא על חלונות 8, כך שלפתח לחלונות 8 פותח לנו הרבה מאוד יכולות בעתיד. כולם יהיו שם – ואם אתם רוצים להקדים את כולם – בואו ללמוד וללמד בפורום החדש!

שמרו את התאריך - יום פתוח במיקרוסופט - פיתוח לחלונות 8 בהטמל5

פורסם בתאריך Jun 20 2012, 09:33 PM על ידי eladkatz

ביום שני הקרוב אני מעביר יום פתוח במיקרוסופט על פיתוח בHTML5 לחלונות8.
לרישום לחצו כאן.


דרישות קדם הן לדעת HTML ו JS ברמה בסיסית לפחות. חלונות 8 מאפשרת למפתחי Web עם הכירות עם HTML5 ו- JavaScript לפתח אפליקציות מטרו עשירות ולהרגיש כאזרחים מהשורה הראשונה.
ביום עיון זה, נלמד על עקרונות הפיתוח ל- Windows 8 ב- HTML5, נראה איך ניתן לקחת את הידע והניסיון מעולם ה- Web לעולם ה- Desktop ונבין את ההבדלים בין העולמות. נכיר את WinJS – ספריית ה- JavaScript של מיקרוסופט המכילה פקדים ורכיבים מותאמים לסוג החדש של האפליקציות, ואת WinRT – שכבת ה- API החדשה לגישה ליכולות של Windows מקוד JavaScript.

תכנות בהטמל5 לחלונות 8 - איך להוסיף תמיכה בשפות מימין לשמאל כמו עברית

פורסם בתאריך Jun 13 2012, 04:07 AM על ידי eladkatz
הפוסט הזה מעודכן לגרסת ה RP של חלונות. בשביל תמיכה מימין לשמאל בגרסה הסופית של חלונות יש פוסט עדכני יותר.


איך מוסיפים תמיכה בשפות שנכתבות מימין לשמאל בחלונות 8?

שאלה שאני נשאל לעיתים קרובות היא איך מתאימים אפלקציות הטמל5 לעבודה בעברית בחלונות8.
אחד החלקים הכי כיפים בכתיבה לחלונות 8 זה שכל הידע שלנו בהטמל רלוונטי גם כאן, ולפיכך היינו יכולים להתאים ל RTL בכל הדרכים הרגילות. אבל.. אנחנו עובדים בהטמל5, לא 4, לפיכך אפשר לעבוד בצורה אפילו יותר חכמה ממה שרגילים אליה – ע”י תגית הCSS3 לשפת ממשק - -ms-lang (זהו פיצ’ר לא סגור של הטמל5 ולכן הקידומת –ms).

 

 

איך מגדירים שפת ממשק?

ניצור אפליקציית גריד חדשה:

image

כשנריץ אותה, נוכל לראות שהיא מותאמת לשפות Left To Right, ולפיכך זה לא יתאים לעברית:

image

נסגור את האפליקציה, ונכנס להגדרות של הפרוייקט:

image

תחת שפת ברירת המחדל (default language) יהיה כתוב en-US:

image

נשנה את זה לעברית – he-IL:

image

במידה ונריץ את האפליקציה, נראה שאכן האפליקציה הפכה להיות מימין לשמאל, אבל זה לא נראה טוב:

image

איך זה עובד?

אם נכנס לקובץ ה CSS של WinJS נוכל לראות משהו מעניין

image

בתוך הקובץ (שורה 30) יש שורה מעניינת, שעושה שימוש ב –ms-lang:

image

-ms-lang הוא פסדו סלקטור של שפה. בקוד לעיל, מוגדר כי במידה ואנו באחת משפות הממשק המצויינות (עברית, ערבית, ועוד כל מיני שפות RTL), אזי direction יקבע ל rtl. היופי כאן הוא שקובץ *אחד* יכול להכיל הגדרות לכל שפה שבעולם. זה מפשט כתיבה לכמה שפות לאין שיעור (וכל מי שהתנסה בזה, יודע שזה לא כיף גדול).

 

 

אז למה זה לא נראה טוב?

מסתבר שקבצי ה CSS של winJS כתובים ממש טוב, אבל קבצי ה CSS “שלנו” שנוצרו ע”י ויז’ואל סטודיו לא מתייחסים לתגית הזו (אין שימוש בפסדו סלקטור הזה בהם). כדוגמא, אם נסתכל בקובץ default.css שנמצא תחת התיקייה CSS, נוכל לראות את הגדרת ה CSS הבאה:

image

כפי שאפשר לראות, margin-left נקבע להיות 39 פיקסלים. הסלקטור CSS הזה “תופס” את כפתור החזור, ונותן לו ריווח של 39 פיקסלים משמאל, רק שבמידה וקבענו את השפה להיות עברית, לא רשום בשום מקום שזה אמור להיות ההפך. זו הסיבה שכפתור החזור נראה כך:

image

 

 

איך מסדרים את זה?

הפתרון פשוט בצורה מפתיעה. כל מה שצריך לעשות זה להגדיר עוד סלקטור, שיתפוס את הכפתור אך ורק במצב של –ms-lang של שפות ימין לשמאל, ולרשום בו שהריווח יהיה מצד ימין ולא שמאל:

image

עכשיו, כשנריץ, נוכל לראות שהכפתור התמקם מחדש במקום הנכון!

image

כל מה שנותר לעשות זה לעבור על כל קבצי ה CSS שנוצרו אוטומאטית ע”י ויז’ואל סטודיו, ולהוסיף את התיקון הזה בכל מקום. (כל מה שצריך לתקן זה ריווח שמאלי לימני וריווח ימני לשמאלי, וסיימנו).

כאלו קבצים יש ארבעה:

default.css
groupedItems.css
groupDetail.css
itemDetail.css

צריך לעבור על כולם ולהפוך בכל מקום את הריווחים ע”פ השפה, וסיימנו!

נריץ את האפליקציה פעם אחרונה, ונראה כי הכל מסודר כפי שרצינו:

image

את הקבצים המתוקנים אפשר להוריד מכאן

ואת הפרוייקט המלא אפשר להוריד מכאן

קניתם אייפד ועכשיו אתם תקועים עם iOS? אל דאגה, חלונות 8 בדרך אליכם!

פורסם בתאריך Jun 09 2012, 05:45 PM על ידי eladkatz

בעלים של אייפד או אנדרויד טאבלט, אין צורך יותר להיות תקועים עם מערכת הפעלה אנכרוניסטית!

טוב, אז לא באמת. זה לא בדיוק חלונות 8, אלא יותר אפליקציה שמדמה את ממשק המטרו של חלונות 8, ומאפשרת לחוות חלקים משמעותיים של מערכת ההפעלה (זה לא יעבוד מושלם, אבל זה יעבוד מספיק טוב בשביל לגרום לכם להצטער עוד יותר שלא חיכיתם לטאבלטים של חלונות 8, ויש למה לחכות. באמת.)

 

Behaviors - חלק 0 - למה זה הפיצ'ר החשוב ביותר ב WPF4, ולמה הוא קריטי למימוש של MVVM

פורסם בתאריך Jun 08 2012, 09:29 AM על ידי eladkatz

הפיצ’ר החזק ביותר שהתוסף ל WPF4 – התנהגויות (Behaviors) הוא פיצ’ר שמפתיע בחוזק שלו.

Behaviors מאפשרים הוספת התנהגות “מבחוץ” לקונטרולים, (טיפה מזכיר את Extension Methods שיכולים להוסיף למחלקות קיימות ב C#).
את ההתנהגויות הללו אפשר לכתוב על מנת להרחיב פונקציונאליות של קונטרולים קיימים, בצורה מאוד ריוזאבילית (reuse קוד גבוה מאוד).

(כדוגמא – בפוסט הקודם הזה אפשר לראות איך בכמה שניות אפשר להוסיף התנהגות של גרירה לאלמנטים בחלון).

את ההתנהגויות הללו אפשר להוסיף לקונטרולים בצורה דקלרטיבית (ע”י XAML, ללא הוספה של Code Behind), מה שהופך את כל הסיפור לגם *מאוד* אלגנטי, וגם לפתרון מעולה לכמעט כל בעיה שמתעוררת ב MVVM.

ב MVVM שולטים על ה View מתוך ה ViewModel אך ורק ע”י DataBinding ו Commands. רק שלא על הכל ניתן לשלוט סה”כ ע”י DataBinding ו Commands.

לדוגמא, אם נרצה לשלוט מה ViewModel בכמות הטקסט שנבחר בתוך TextBox – אין כזה DependencyProperty בכלל, ולפיכך אין שום אפשרות לשלוט בזה ע”י DataBinding. אלו מסוג המקומות שמאוד מתסכלים מפתחים שרק מתחילים ב MVVM.

דוגמא נוספת היא Commands. בשביל להרים Command ב View, הקונטרול חייב לתמוך ב Commands, כשרוב הקונרולים לא תומכים בזה (תומכים בזה אך ורק ButtonBase ו MenuItem). מה אם אני רוצה לדעת על אירוע שמתבצע על TextBox? אני טיפה תקוע…
גם הקונטרולים שכן תומכים כבר ב Commands, כמו כפתור – ירימו Command אך ורק בתגובה ללחיצה עליהם. במידה ואנו רוצים לדעת על אירוע אחר שהתרחש על הקונטרול ולהגיב אליו עם Command – עוד פעם – אני תקוע.

 

Behaviors זה הפתרון המושלם והאלגנטי ביותר לכל הבעיות הללו, ולכתוב ב WPF ללא שימוש ב Behaviors פשוט לא הגיוני

בפוסטים הבאים נראה איך ב MVVM אפשר לפתור את כל הבעיות הנ”ל.

בפוסט הבא נראה איך מוסיפים Behaviors מבלנד

Behaviors חלק 3 - יצירת ב Custom Behavior משלנו

פורסם בתאריך Jun 08 2012, 09:13 AM על ידי eladkatz
בפוסט הקודם ראינו איך להשתמש ב Behaviors מתוך ויז'ואל סטודיו

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

על מנת ליצור behavior, יש לממש את המחלקה Behavior של T. כשבמקום T נשים את מחלקת הבסיס אליה נרצה לחבר את ה Behavior. לדוגמא:

public class HighlightBehavior : Behavior<Control>
{
 
}

ה Behavior יחובר למחלקה קונטרול, מה שאומר שאפשר להשתמש ב Behavior הזה בכל מחלקה שיורשת מקונטרול.

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

public class HighlightBehavior : Behavior<Control>
    {
        protected override void OnAttached()
        {
            
 
 
        }
    }

 

במקרה שלנו, ננסה ליצור התנהגות מאוד פשוטה – התנהגות של שינוי צבע כשהעכבר עולה מעל הקונטרול (ולפיכך השם שבחרנו – HighlightBehavior).

נוסיף למתודה הזו את הקוד הבא:

this.AssociatedObject.MouseEnter += new MouseEventHandler(AssociatedObject_MouseEnter);
this.AssociatedObject.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave);

this.AssociatedObject הוא הקונרטול עליו ההתנהגות (Behavior) “יושבת”. במקרה שלנו הוא מסוג קונטרול.

הרישום הוא לאירועים MouseEnter ו MouseMove בשביל שנוכל לשנות את צבע הרקע של הקונרול בכניסה וביציאה של העכבר ממנו.

כך יראו המתודות שמטפלות באירועים הנ”ל:

void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
{
    this.AssociatedObject.Background = Brushes.White;
}
 
void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
{
    this.AssociatedObject.Background = Brushes.Blue;
}

והקוד המלא של ההתנהגות יראה כך:

 

public class HighlightBehavior : Behavior<Control>
{
    protected override void OnAttached()
    {
 
        this.AssociatedObject.MouseEnter += new MouseEventHandler(AssociatedObject_MouseEnter);
        this.AssociatedObject.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave);
 
    }
 
    void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
    {
        this.AssociatedObject.Background = Brushes.White;
    }
 
    void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
    {
        this.AssociatedObject.Background = Brushes.Blue;
    }
}

קצר ולעניין.

שימוש בהתנהגות שלנו יעבוד בדיוק כמו שימוש בהתנהגות רגילה:

 

<Grid>
    <TextBox Height="39" HorizontalAlignment="Left" Margin="59,47,0,0" Name="textBox1" VerticalAlignment="Top" Width="129" >
        <i:Interaction.Behaviors>
            <my:HighlightBehavior />
        </i:Interaction.Behaviors>
    </TextBox>

ה TextBox עכשיו יקבל את ההתהגות שכתבנו. (TextBox יורש מקונטרול. במידה והיינו שמים את ההתנהגות על מחלקה שלא יורשת מקונטרול היינו מקבלים שגיאה).

החלק החזק של ההתנהגות מגיע עכשיו – אפשר לשים אותה כמה פעמים שנרצה על קונרולים בחלון, ונקבל התנהגות שה Code Reuse שלה מאוד גבוה. כותבים פעם אחת, משתמשים כמה שרוצים:

 

<Grid>
    <TextBox Height="39" HorizontalAlignment="Left" Margin="59,47,0,0" Name="textBox1" VerticalAlignment="Top" Width="129" >
        <i:Interaction.Behaviors>
            <my:HighlightBehavior />
        </i:Interaction.Behaviors>
    </TextBox>
    <TextBox Height="39" HorizontalAlignment="Left" Margin="261,47,0,0" Name="textBox2" VerticalAlignment="Top" Width="129" >
        <i:Interaction.Behaviors>
            <my:HighlightBehavior />
        </i:Interaction.Behaviors>
    </TextBox>
    <TextBox Height="39" HorizontalAlignment="Left" Margin="89,148,0,0" Name="textBox3" VerticalAlignment="Top" Width="129" >
        <i:Interaction.Behaviors>
            <my:HighlightBehavior />
        </i:Interaction.Behaviors>
    </TextBox>
    <CheckBox Content="CheckBox" Height="46" HorizontalAlignment="Left" Margin="278,145,0,0" Name="checkBox1" VerticalAlignment="Top" Width="167">
        <i:Interaction.Behaviors>
            <my:HighlightBehavior />
        </i:Interaction.Behaviors>
 
    </CheckBox>
</Grid>

 

עכשיו כשנעלה מעל כל אחד מהקונטרולים נראה שהוא משנה את הצבע. בין אם זה ה TextBox -

image

ובין אם זה הצ’קבוקס (הריבוע הכחול הקטן זה כל הרקע שלו).

 

image

 

כמובן שהיינו יכולים לשים קוד הרבה יותר מורכב ומעניין בתוך ההתנהגות. בפוסטים הבאים נראה התנהגויות מאוד מעניינת שאפשר לכתוב.

את ההתנהגות שכתבנו אפשר להוסיף גם מבלנד:

 

image

וכך נראה בלנד לאחר שגררנו את ההתנהגות על ListBox שהוספנו לחלון:

 

image

בלנד אפילו מבין שאפשר להוסיף את ההתנהגות אך ורק למחלקה שיורשת מקונטרול, ולפיכך בכלל לא יאפשר הוספה של ההתנהגות על כל דבר אחר (Rectangle לדוגמא)

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

את הקוד ניתן להוריד מכאן - http://sdrv.ms/LhAezB

בפוסט הבא נכיר סוג נוסף של Behaviors שמתנהג טיפה שונה, ומאפשר יותר שליטה על *מתי* תקרה ההתנהגות

קוד ולינקים חשובים להרחבה נוספת לסיום קורס פיתוח בחלונות 8 בהטמל 5

פורסם בתאריך Jun 07 2012, 08:06 PM על ידי eladkatz

תודה לכל באי הקורס בפיתוח לחלונות 8 – היה לי ממש כיף ללמד את הקורס הזה – במיוחד בהתחשב שאתם כמעט הראשונים בעולם שעוברים קורס כזה.

כיסינו המון חומר: WinJS, קונטרולים, Blend5, עבודה עם jQuery, פיצ’רים חדשים של HTML5, מנגנון הריצה של האפליקציות, Design Patterns של ג’אוה סקריפט ועוד.
היה לנו קצב ממש טוב, והספקנו לא מעט – יש הרבה מאוד מה להרחיב בנושא שלא הספקנו. כאמור, בקרוב אעלה סדרת פוסטים על פיתוח לחלונות 8 בגרסת ה RC ותוכלו להתעדכן בדברים שלא הספקנו להכנס אליהם.

את הקוד שיצרנו במהלך הקורס אפשר להוריד מכאן - http://sdrv.ms/KKGHFI

בנוסף, להלן רשימת לינקים לדברים שהזכרנו במהלך הקורס שכדאי לבדוק:

1. KnockoutJS -
  http://knockoutjs.com/ 


2. התקנת חלונות דרך VHD – בבלוג המעולה של סקוט הנסלמן - http://www.hanselman.com/blog/GuideToInstallingAndBootingWindows8DeveloperPreviewOffAVHDVirtualHardDisk.aspx


3. ג’אווה סקריפט – Design Pattern.
http://addyosmani.com/resources/essentialjsdesignpatterns/book/

4. לא רלוונטי עדיין אבל שווה הצצה – Dart -
http://www.dartlang.org/

5. הורדה של חלונות 8 RP -
http://windows.microsoft.com/en-US/windows-8/download


6. הורדה של ויז’ואל סטודיו 2012 RC -
http://www.microsoft.com/visualstudio/11/en-us/downloads


7. הפורומים החדשים של MSDN ישראל – בקרוב יפתח פורום לחלונות 8. שם תמיד הכי קל להשיג אותי -
p://social.msdn.microsoft.com/Forums/he-IL/wpfhe/threads (הלינק הוא לפורום WPF שאני מנהל – שם תמיד אפשר למצוא אותי, עד שיפתח הפורום החדש לחלונות 8)

More Posts Next page »