Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S...

9
Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM. In plus se creaza si o comanda in WPF. Clasele implicate in acest pattern sunt date in figura de mai jos. Mai multe informatii la adresa: http://msdn.microsoft.com/en- us/library/gg405484(v=pandp.40).aspx Diagrama de clase a proiectului pe care il vom crea

Transcript of Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S...

Page 1: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

Laborator MVVM

Scop: Crearea unei aplicatii ce exemplifica paternul MVVM. In plus se creaza si o comanda

in WPF.

Clasele implicate in acest pattern sunt date in figura de mai jos.

Mai multe informatii la adresa: http://msdn.microsoft.com/en-

us/library/gg405484(v=pandp.40).aspx

Diagrama de clase a proiectului pe care il vom crea

Page 2: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

1. Creare proiect WPF.

2. Creare foldere: Models, ViewModels, Views.

Modelul se va gasi in folder Models. In cazul nostru modelul este constituit din clasa

Customer. Obiectul creat din Customer trebuie sa aiba posibilitatea de a notifica sistemul

despre schimbarile survenite in starea sa: modificarea unei proprietati in cazul nostru. Din

acest motiv clasa Customer implementeaza interfata INotifyPropertyChanged.

3. Adaugam clasa Customer in Models.

using System;

using System.ComponentModel;

namespace MVVM.Models {

public class Customer:INotifyPropertyChanged

{

private string _name;

public Customer(string customername)

{ _name = customername;

}

// Cand se modifica _name se va apela metoda OnPropertyChanged(“Name”);

public string Name

{

get { return _name; }

set { _name = value;

OnPropertyChanged("Name");

}

}

private void OnPropertyChanged(string name)

{

// Daca s-a atasat o metoda pentru evenimentul

// PropertyChangedEventHandler, atunci se va executa acea metoda.

PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)

handler(this, new PropertyChangedEventArgs(name));

}

public event PropertyChangedEventHandler PropertyChanged;

}

}

4. Adaugam clasa CustomerViewModel in folder ViewModels.

CustomerViewModel mentine o referinta la Customer din Models (se instantiaza

Customer in constructor), defineste o proprietate (get) ce returneaza referinta la Customer

si o metoda pentru salavrea datelor, numita SaveChanges().

using System;

using System.Diagnostics;

using System.ComponentModel;

Page 3: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

using System.Windows.Input;

using MVVM.Models;

namespace MVVM.ViewModels

{

internal class CustomerViewModel

{

/// <summary> /// Initializeaza o noua instanta a clasei CustomerViewModel

/// </summary>

public CustomerViewModel()

{

_Customer = new Customer("Ioan");

// UpdateCommand = new CustomerUpdateCommand(this);

}

/// <summary>

/// Data membru ce mentine o instanta a clasei Customer.

/// Este accesata prin intermediul proprietatii Customer

/// </summary>

private Customer _Customer;

/// <summary>

/// Proprietate ce returneaza Customer

/// </summary>

public Customer Customer {

get { return _Customer; } }

/// <summary>

/// Metoda ce salveaza datele in baza de date.

/// Aici se afiseaza un text pentru a vedea ca metoda se apeleaza.

/// </summary>

public void SaveChanges()

{

Debug.Assert(false, String.Format("{0} a fost actualizat.",

Customer.Name)); }

}

}

Rezolvam referintele.

Page 4: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

In folder Views adaugam un articol de tip Window (WPF), numit

MainWindowView.xaml.

Stergem <Grid></Grid> si inlocuim cu

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">

<Label Content="Customer name"/>

<TextBox Width="150" />

<Button>Update</Button>

</StackPanel>

Codul din MainWindowView.xaml este cel de mai jos (atentie la namespace) .

<Window x:Class="MVVM.MainWindowView"

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

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

Title="MainWindowView" Height="300" Width="483"> <StackPanel Orientation="Horizontal" VerticalAlignment="Top">

<Label Content="Customer name"/>

<TextBox Width="150" /> <Button>Update</Button>

</StackPanel>

</Window>

In MainWindowView.xaml.cs adaugam in constructor , dupa InitializeComponent():

DataContext = new CustomerViewModel()

Este necesar pentru binding.

Deci avem:

public MainWindowView()

{

InitializeComponent();

DataContext = new CustomerViewModel();

}

iar TextBox-ul va avea asociat numele Customer. Modificam in MainWindowView.xaml

pentru TextBox pentru a prelua valoarea proprietatii Name din Customer in proprietatea

Text.

<TextBox Name="customer" Text ="{Binding Customer.Name}" Width="150" />

Lansam in executie aplicatia.

Va aparea doar o fereastra si fara controale.

Deschidem App.xaml si StartupUri va avea urmatorul continut:

StartupUri="Views/MainWindowView.xaml"

Acest lucru inseamna ca fereastra pe care o va crea si afisa Application este cea din

folder Views cu numele MainWindowView.xaml.

Page 5: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

Lansam aplicatia.

Cand facem clic pe butonul Update nu se intampla nimic. Nu am tratat evenimentul Clic

al butonului. Nu vom trata acest eveniment.

Vom atasa o comanda pe acest buton. Numim aceasta comanda UpdateCommand si o

atasam la buton folosind binding.

Cream clasa pentru comanda.

Cream mai intai un folder numit Commands, iar in acest folder cream clasa

CustomerUpdateCommand.cs derivata din ICommand. Interfata are doua metode

Execute si CanExecute, si un eveniment CanExecuteChanged, pe care le

implementam. Detalii ICommand in MSDN.

CustomerUpdateCommand trebuie sa aiba referinta la CustomerViewModel. Vom injecta

acest obiect prin constructor.

Metoda Execute va apela SaveChanges() din CustomerViewModel.

CanExecute returneaza true daca comanda poate fi executata si false in caz contrar.

In cazul nostru CustomerViewModel are informatia daca comanda se poate executa sau nu

(scenariu: daca nu e completat TextBox atunci nu se executa).

Vom crea in CustomerViewModel o proprietate (metoda), numita CanUpdate, ce

returneaza bool conform specificatiei de mai sus. Codul este:

public bool CanUpdate

{

get

{

if (Customer == null) return false;

return !String.IsNullOrWhiteSpace(Customer.Name);

}

}

Page 6: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

Codul complet din CustomerUpdateCommand este:

internal class CustomerUpdateCommand:ICommand

{

// Mentine referinta la un obiect CustomerViewModel injectat prin constructor.

private CustomerViewModel _ViewModel;

public CustomerUpdateCommand(CustomerViewModel viewmodel)

{

_ViewModel = viewmodel; }

// Intreaba CustomerViewModel daca poate executa comanda

bool ICommand.CanExecute(object parameter)

{

return _ViewModel.CanUpdate;

}

// MSDN. The CommandManager class defines the Commanding Execute/CanExecute

// Events and also its RoutedEventHandlers which delegates them to

// corresponding ComamndBinding.Execute/CanExecute EventHandlers.

/// <summary>

/// Cand atribuim comanda la un control, aceasta subscrie la

/// evenimentul CanExecuteChanged.

/// Daca o "redirectam" la evenimentul CommandManager.RequerySuggested,

/// controlul va fi notificat ori de cate ori

/// CommandManager.RequerySuggested este apelat.

/// </summary>

event EventHandler ICommand.CanExecuteChanged

{

add { CommandManager.RequerySuggested += value; }

remove { CommandManager.RequerySuggested -= value; }

}

// Apel metoda salvare date din CustomerViewModel.

void ICommand.Execute(object parameter)

{

_ViewModel.SaveChanges();

}

}

Observatie

CommandManager in MSDN:

Provides command related utility methods that

register CommandBinding and InputBinding objects for class owners and commands, add

and remove command event handlers, and provides services for querying the status of a

command.

iar evenimentul RequerySuggested:

Occurs when the CommandManager detects conditions that might change the ability of a

command to execute.

Page 7: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

In MainWindowView.xaml pentru Button modificam astfel (atasam comanda)

<Button Name="update" Content="Update" Command="{Binding UpdateCommand}"/>

UpdateCommand va fi o proprietate in CustomerViewModel ce returneaza ICommand.

Va fi setata in constructorul clasei CustomerViewModel.

In CustomerViewModel adaugam:

// Returneaza UpdateCommand pentru ViewModel

public ICommand UpdateCommand

{

get;

private set; }

Setam valoarea pentru UpdateCommand in constructorul clasei CustomerViewModel,

astfel:

UpdateCommand = new CustomerUpdateCommand(this);

Dupa aceste modificari, codul complet din CustomerViewModel este:

internal class CustomerViewModel

{

/// <summary>

/// Initializeaza o noua instanta a clasei CustomerViewModel

/// </summary>

public CustomerViewModel()

{ _Customer = new Customer("Ioan");

UpdateCommand = new CustomerUpdateCommand(this);

}

/// <summary>

/// Data membru ce mentine o instanta a clasei Customer

/// </summary>

private Customer _Customer;

/// <summary> /// Proprietate ce returneaza Customer

/// </summary>

public Customer Customer {

get { return _Customer; }

}

/// <summary> /// Metoda ce salveaza datele in baza de date.

/// Aici se afiseaza un text pentru a vedea ca metoda se apeleaza.

/// </summary> public void SaveChanges()

{

Debug.Assert(false, String.Format("{0} a fost actualizat.",

Customer.Name));

}

/// <summary> /// Get the UpdateCommand for ViewModel.

/// </summary>

public ICommand UpdateCommand

Page 8: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei

{

get;

private set;

}

public bool CanUpdate {

get

{ if (Customer == null)

return false;

return !String.IsNullOrWhiteSpace(Customer.Name);

}

// set;

}

}

Rezolvam referintele si rulam aplicatia.

Butonul Update nu este Enable/Disable dupa cum TextBox este completat sau nu.

Functionalitatea se rezolva prin adaugarea proprietatii

UpdateSourceTrigger=PropertyChanged la TextBox.

Cod complet:

<TextBox Name="customer" Text ="{Binding Customer.Name,

UpdateSourceTrigger=PropertyChanged}" Width="150" />

Rulam aplicatia.

Adaugam codul de mai jos in MainWindowView.xaml (in fapt numai cele doua combo

box-uri).

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">

<Label Content="Customer name"/>

<TextBox Name="customer" Text ="{Binding Customer.Name,

UpdateSourceTrigger=PropertyChanged}" Width="150" />

<ComboBox IsEditable="True" Text ="{Binding Customer.Name,

UpdateSourceTrigger=PropertyChanged}" Width="150" />

<ComboBox ItemsSource="{Binding Customer.Name}" Text ="{Binding Customer.Name,

UpdateSourceTrigger=PropertyChanged}" Width="150" />

<Button Name="update" Content="Update" Command="{Binding UpdateCommand}"/>

</StackPanel>

Rulam.

Page 9: Laborator MVVM Scop: Crearea unei aplicatii ce exemplifica paternul MVVM…iasimin/Laborator C S H... · 2014-05-16 · Modelul MVVM si Command WPF May 14, 2014 Ioan Asiminoaei Lansam

Modelul MVVM si Command WPF May 14, 2014

Ioan Asiminoaei