MVVM Part 4 – MVVM-Light

19 בDecember 2012

3 תגובות

MVVM part 4 – MVVM Light

דיברנו על MVVM  והזכרתי בפוסט הראשון (מבוא לMVVM),  שארחיב על הספריות הקיימות שמספקות לנו תשתית
נוחה לעבודה עם
MVVM
, אז אם בא לכם להיכנס
לעולם ה
MVVM , מומלץ בחום להתחיל עם MVVM Light, הוא פשוט, קליל, נוח לעבודה

וחוסך זמן פיתוח.

לMVVM Light ישנו toolkit חמוד שיתלבש לכם על הVisual Studio , ממש לא חייבים להתקין
אותו ממי שפוחד מתוספות , אלא פשוט לקחת את ה
DLL  שלהם ולעשות לו

Reference לפרויקט, אם תרצו  להתקין את הtoolkit כנסו לפה  ותזרמו עם המדריך.

בVS 2010 זה מתלבש יפה על התוכנה , ב 2012 VS זה נראה לי קצת יותר מורכב,

בכל מקרה אני מעדיף
דווקא להוריד את ה
DLL
 ולעבוד מולו. נסו לקחת את זה מפה

כי אני לא אוהב Extensions על התוכנה וודאי עם זה לזמן מוגבל ואני לא זקוק
לפתוח פרוייקטים כאלה יום יום.

לאחר ההורדה נצמיד
רפרנס ל
DLL   ונוסיף בקוד את החלק הזה.

        using GalaSoft.MvvmLight.Command; Messaging;

                                                                                                     
GalaSoft.MvvmLight.Messaging 
                                    

                                                                 

זה ייתן לנו  Command מוכן לשימוש (relayCommand) ולא נצטרך לבנות אחד משלנו (כמו שהצגתי
בפוסט
Wpf
command
), ובנוסף שימוש במנגנון  לתקשורת בין viewModels  באמצעות Events  כמו שהסברתי בפוסט הראשון  בסדרה- מבוא לMVVM, אז בMVVM Light זה נקרא Messenger.

דבר נוסף שנשתמש בו
בדוגמא זה
Service
Locator
(שווה להכיר את המושג
ולקרוא עליו בנפרד
כאן)

אז מה זה service Locator ?? ניזכר קצת ברעיון של DataContext בWPF-MVVM..

זה אומר הרכיב שמקשר
בין ה
View לViewModel , ולפעמים קצת קשה לנו
ללכת להגדיר

את כל הטיפול בקשר
הזה בעצמינו ונרצה עזרה, לפעמים נרצה להשתמש ב
ViewModle אחד יותר מפעם אחת, וזה גם ישמור לנו על הCodebehind נקי בלי השורה  dataContext = XViewMode , כי לא כדאי כ”כ להחזיק קוד כזה על הView עדיף להשאיר את האחריות לחיבור בין View-Viewmodel לתשתית. (יהיה לי קישור לData context מתוך הxaml והוא יצביע לקלאס)

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

ובוא נציג אפליקציה
בסיסית שמשתמשת ב
MVVM
Light
עם שלושת החלקים המרכזיים
שלה (
Messenger, locator, RelayCommannd).

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

לא כ”כ חשוב מה
עושה האפליקציה רק לצורך הדוגמא יהיה לי חלון לחתולים וחלון לכלבים, כאמור לכל אחד
יהיה
View+ViewModel משלו, ואנחנו נרצה להעביר ביניהם הודעות..(
באמצעות
Messanger )

נניח שהתחרות כרגע
היא כמה חתולים וכלבים יש ברחוב סומסום, כמובן כל צד רוצה לנצח, ולכן להגביר את
הילודה, בתמימות של בעלי חיים אין קלפים סודיים, ולכן כל קבוצה מודיעה לקבוצה
היריבה כמה חיות יש כרגע ב”קהילה” ולהיפך.. (באמצעות מנגנון ה
Events -Messanger)

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

 

1.   נפתח פרוייקט מסוג WPF,

2.   נוסיף מהתפריט שני views (חלונות) משלנו, כדאי
להתרגל לשימוש נכון בשמות, מקובל לתת שם לחלון בתוספת הסיומת
View. לכן יהיו לי CatsView , DogsView.

3.  
נוסיף מהתפריט שני קלאסים עבור ViewModels גם כאן מומלץ להתרגל לנוסחה הבאה שם הView רק בתוספת Model ז”א יהיו לי עכשיו
גם
CatsViewModel,DogsViewModel.

4.   נוסיף לפרוייקט רפרנס לDLL  של GalaSoft.MVVMLight ולכל אחד מהקלאסים האלה
אני מוסיף את ה
Command והNessaging של הDLL (using)

5.  
בנוסף אני מממש את ה INotifyPropertyChanged המפורסם שזה בעצם כלי שמהווה מימוש של Observer Pattern ותומך בעדכון הView על שינויים בViewModel באמצעות הטכניקה של DataBinding.  כך
ייראו ה
ViewModels
 כרגע:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Text;

using GalaSoft.MvvmLight.Command;

using GalaSoft.MvvmLight.Messaging;

 

namespace MVVM_Light_Demo.ViewModels

{

  public  class CatsViewMpdel:INotifyPropertyChanged

    {

        public event PropertyChangedEventHandler PropertyChanged;

    }

 

  public  class DogsViewModel:INotifyPropertyChanged

    {

        public event PropertyChangedEventHandler PropertyChanged;

    }

 

}

 

6.   למעשה אני צריך לתמוך
גם במסך פתיחה (
bootStraper בשפה המקצועית – נקודת כניסה לאפליקציה), כי
מישהו צריך להרים את המשחק ולהפעיל את שני החלונות כזכור הם לא מכירים זה את זה
ולא פונים ישירות אחד לשני. (זוכרים את שני החוקים הלא  כתובים של
MVVM?? )  אז נשתמש ב Main Window או בכל חלון אחר ואני לא אבזבז זמן להגדיר
אותו בשיטת ה
MVVM   כמו את חלונות המשחק אבל בקיצור אני יוצר
אינסטנס לשני צדדי המשחק ונמשיך משם אז ככה נראה הקוד של חלון הפתיחה (בצד ה
xaml יש סתם כפתור) :

  public partial class StartGameView : Window

    {

        public StartGameView()

        {

            InitializeComponent();

        }

 

        private void Button_Click_1(object sender, RoutedEventArgs e)

        {

            CatsView cats = new CatsView();

            DogsView dogs = new DogsView();

            cats.Show();

            dogs.Show();

            this.Close();

        }

                                                               { 

 

 

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

נתחיל בחיבור לViewModel. זוכרים את הLocator  ? זה הזמן להגדיר אותו
נניח בצורה הבאה:

נוסיף לפרוייקט קלאס שנקרא locator שבתוכו יהיו בס”ה
מופע סינגלטון של כל ה
ViewModels שלנו בתכנית. עם פרופרטי
תואם שמחזיר אותם. זה נראה כך:

public class ViewModelLocator

    {

       private static DogsViewModel _dogsViewModel;

        public DogsViewModel DogsViewModel

        {

            get

            {

                if(_dogsViewModel==null)

                    _dogsViewModel = new DogsViewModel();

                return _dogsViewModel;

            }

        }

 

        private static CatsViewMpdel _catsViewmodel;

        public CatsViewMpdel CatsViewModel

        {

            get

            {

                if (_catsViewmodel == null)

                    _catsViewmodel = new CatsViewMpdel();

                return _catsViewmodel;

            }

        }

   
                                                                 {   

כדי שנוכל לפנות לדבר
הזה מה
Views שלנו הוא צריך להיכנס לResources של הפרוייקט,  אני מוסיף אותו לapp.xaml וזה ייראה כך:

<Application x:Class=”MVVM_Light_Demo.App”

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

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

             xmlns:DataContext=”clr-namespace:MVVM_Light_Demo.Locator”

             StartupUri=”StartGameView.xaml”>

    <Application.Resources>

        <DataContext:ViewModelLocator x:Key=”Locator”/>

    </Application.Resources>

</Application>

 

7.   בוא נבנה רגע את מה שחסר בViewModel לפני שנחבר אותו לView:

אנו צריכים 2 Commands אחד ל”הוספת גור”
והשני להכרזה על כמות החיות אצלינו.

כמו כן 2 משתנים אחד לגמה גורים יש אצלי ואחד מתעדכן בהודעות ששולח
היריב.

 אני מוסיף לViewModels שלי את הנתונים הבאים:

private RelayCommand informMembersCommand;

        public RelayCommand InformMembersCommand

        {

            get

            {

                if (informMembersCommand == null)

                {

                    informMembersCommand = new RelayCommand(SendMessage);

                }

                return informMembersCommand;

            }

        }

 

        private RelayCommand addBabyCommand;

        public RelayCommand InformMembersComma

        {

            get

            {

                if (addBabyCommand == null)

                {

                    addBabyCommand = new RelayCommand(AddMember);

                }

                return addBabyCommand;

            }

        }

        private int membersCounter;

        public int MembersCounter

        {

            get { return membersCounter; }

            set {

                membersCounter = value;

                PropertyChanged(this, new PropertyChangedEventArgs(“MembersCounter”));

            }

        }

        private int rivalsCounter;

        public int RivalsCounter

        {

            get { return rivalsCounter; }

            set

            {

                rivalsCounter = value;

                PropertyChanged(this, new PropertyChangedEventArgs(“RivalsCounter”));

            }

        }

        private void AddMember()

        { this.MembersCounter++; }

     

        private void SendMessage()

        { }

      

        private void GetMessage(int i)

        {

            this.RivalsCounter = i;

      }

                                                                                         

 

 

   

 

8.  
מה שעדיין חסר זה השימוש הפנימי במנגנון המסרים ואת זה אני מוסיף בצור
הבאה:

private void SendMessage()

        {

            Messenger.Default.Send<int>(this.MembersCounter,“dogs”);

                                                               {

       private void SendMessage()

        {

            Messenger.Default.Send<int>(this.MembersCounter,“cats”);

        }

 

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

(החתולים נרשמים להודעה של הכלבים ולהיפך)

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

public CatsViewMpdel()

        {

            Messenger.Default.Register<int>(this,“cats”, GetMessage);

{        

 

public DogsViewModel()

        {

            Messenger.Default.Register<int>(this,“dogs”, GetMessage);

        }

      

*הערה: אנו שמים לב לנתונים זהים  בשני המסכים חוץ מאשר המסנג’ר , כמובן שמשתמשים
בירושה של
viewModel כמו כל אובייקט אחר אבל לא בדוגמא הזאת..
כרגע אני פשוט לוקח את הקוד הזה ושם אותו בשני 
ה
ViewModels שלי.

 

9.   זהו, נשאר רק הView . לא כ”כ רלוונטי מה
נייצג ב
View שלנו במדוייק, אני יוצר שני views כחלונות של WPF . לכל View יש  1.תיבת טקסט שמתעדכנת
לפי כמות הגורים שהמתחרה מודיע שיש לו, 2. כפתור ל”הוספת גור” 3.כפתור
לשליחת הודעה לעולם מה מספר החיות כרגע בקבוצה 4.תיבת טקסט שבה אני רואה כמה יש
לי..

ארבעת הפרמטרים מחוברים דרך binding לdatacontext של הView , שזה בעצם ה viewModel

למעשה החלק היחיד שחשוב כאן זה החיבור לData Context באמצעות הlocator שבנינו
בהתחלה.
אז שימו לב לשורה :

   

   DataContext=”{Binding Source={StaticResource Locator}, Path=    

 

 

כך נראה קוד הXaml של הView של צד “הכלבים”. 

<Window x:Class=”MVVM_Light_Demo.Views.DogsView”

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

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

        Title=”DogsView” Height=”300″ Width=”300″

                DataContext=”{Binding Source={StaticResource Locator}, Path=DogsViewModel}”>

 

    <Canvas>

        <Image Source=”/Images\dogs.jpg” Height=”148″ Width=”282″ Canvas.Left=”10″ Canvas.Top=”21″></Image>

        <Button Content=”send Message to Cats” Command=”{Binding InformMembersCommand}”  Canvas.Left=”150″
Canvas.Top
=”182″ />

        <Button Content=”add baby dog”
Command
=”{Binding AddBabyCommand}”  Canvas.Left=”37″ Canvas.Top=”182″
/>

        <TextBlock Text=”{Binding RivalsCounter}” Canvas.Left=”131″ Canvas.Right=”100″ Width=”50″ Canvas.Top=”219″/>

        <TextBlock Text=”cats now…”
Canvas.Left
=”131″ Canvas.Right=”100″ Width=”73″ Canvas.Top=”235″
/>

        <TextBlock Text=”{Binding MembersCounter}” Canvas.Left=”130″ Canvas.Right=”100″ Width=”50″ Canvas.Top=”135″/>

        <TextBlock Text=”My Side Number is now…” Canvas.Left=”10″ Canvas.Right=”100″ Width=”120″ Canvas.Top=”135″
/>

    </Canvas>

</Window>

וכך נראה קוד הXaml של הView של צד
“החתולים”.

<Window x:Class=”MVVM_Light_Demo.Views.CatsView”

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

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

        Title=”CatsView” Height=”300″ Width=”300″

        DataContext=”{Binding Source={StaticResource Locator}, Path=CatsViewModel}”>

    <Canvas>

        <Image Source=”/Images\cats.jpg” Height=”125″ Width=”282″ Canvas.Top=”10″></Image>

        <Button Content=”send Message to Dogs” Command=”{Binding InformMembersCommand}”  Canvas.Left=”150″
Canvas.Top
=”182″ />

        <Button Content=”add baby cat”
Command
=”{Binding AddBabyCommand}”  Canvas.Left=”37″ Canvas.Top=”182″
/>

        <TextBlock Text=”{Binding RivalsCounter}” Canvas.Left=”131″ Canvas.Right=”100″ Width=”50″ Canvas.Top=”219″/>

        <TextBlock Text=”dogs now…”
Canvas.Left
=”131″ Canvas.Right=”100″ Width=”73″ Canvas.Top=”235″
/>

        <TextBlock Text=”{Binding MembersCounter}” Canvas.Left=”130″ Canvas.Right=”100″ Width=”50″ Canvas.Top=”135″/>

        <TextBlock Text=”My Side Number is now…” Canvas.Left=”10″ Canvas.Right=”100″ Width=”120″ Canvas.Top=”135″
/>

    </Canvas>

</Window>

זהו . תריצו, תהנו,
ועכשיו אנו יודעים לעבוד גם עם
MVVM Light .

 

 

 

 

 

 

 

 

 

 

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

Leave a Reply

Your email address will not be published. Required fields are marked *

3 תגובות

  1. Dima7 בJanuary 2013 ב 9:47

    the best shortest demo i have ever seen!

    Reply
  2. אברהם23 בJuly 2015 ב 13:18

    ותודה רבה על הפוסטים החשובים בנושאים הללו.

    Reply
    1. אברהם23 בJuly 2015 ב 13:19

      הDLLשצרפת לא קיים עוד.. אשמח אם תעלה אותו חזרה או קישור אחר אליו.

      Reply