« MVVM » : différence entre les versions
De Banane Atomic
Aller à la navigationAller à la recherche
(Une version intermédiaire par le même utilisateur non affichée) | |||
Ligne 31 : | Ligne 31 : | ||
* [https://cinch.codeplex.com/ Cinch] | * [https://cinch.codeplex.com/ Cinch] | ||
* [http://catelproject.com Catel] | * [http://catelproject.com Catel] | ||
= [https://docs.microsoft.com/en-us/windows/uwp/data-binding/displaying-data-in-the-designer Design Time Data] = | |||
<kode lang='xaml'> | |||
<!-- Définition d'un DataContext pour le design time et d'un autre pour le run time --> | |||
<UserControl xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
mc:Ignorable="d" | |||
d:DataContext="{Binding ...}" | |||
DataContext="{Binding ...}"> | |||
<UserControl.Resources> | |||
<CollectionViewSource x:Key="MyCollection" Source="{Binding ...}" d:Source="{Binding ...}" /> | |||
</UserControl.Resources> | |||
<ItemsControl ItemsSource="{Binding Source={StaticResource MyCollection}}" /> | |||
</kode> | |||
{{warn | Le Designer n’exécute pas le code-behind: le DataContext doit être définit dans le XAML.}} | |||
* [[MVVM_Light_Toolkit#ViewModelLocator|ViewModelLocator]] | |||
= [http://jack.ukleja.com/ddesigninstance-in-depth DesignInstance] = | = [http://jack.ukleja.com/ddesigninstance-in-depth DesignInstance] = | ||
Ligne 36 : | Ligne 53 : | ||
<kode lang='xaml'> | <kode lang='xaml'> | ||
<Window xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | <Window xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:local="clr-namespace: | xmlns:local="clr-namespace:MyNamespace" | ||
d:DataContext="{d:DesignInstance local:MainWindowViewModel}"> | d:DataContext="{d:DesignInstance local:MainWindowViewModel}"> | ||
</kode> | </kode> |
Dernière version du 20 juillet 2020 à 16:07
Définition
Séparation de la Vue et du Modèle afin d'améliorer:
- la maintenabilité: tout est rangé au bon endroit, on sait où trouver ce que l'on cherche
- les tests: simuler l'utilisation de l'application en manipulant le Vue-Modèle (Unit Tests + Mock)
- l'extension du code: le code est cloisonné, on peut ajouter ou remplacer des éléments (Design Time Data pour le Designer, Plugins)
Adaptation du modèle MVC à WPF.
Model | les données clientes.
|
View | les éléments visuels.
|
ViewModel | le code logique de la vue (vérification de la saisie)
|
- échanges bi-directionnels entre View et ViewModel grâce au DataBinding.
- View n'a pas accès à Model.
- la View utilise des commandes appeler des méthodes du ViewModel.
Framework
Design Time Data
<!-- Définition d'un DataContext pour le design time et d'un autre pour le run time --> <UserControl xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DataContext="{Binding ...}" DataContext="{Binding ...}"> <UserControl.Resources> <CollectionViewSource x:Key="MyCollection" Source="{Binding ...}" d:Source="{Binding ...}" /> </UserControl.Resources> <ItemsControl ItemsSource="{Binding Source={StaticResource MyCollection}}" /> |
Le Designer n’exécute pas le code-behind: le DataContext doit être définit dans le XAML. |
DesignInstance
Specify the datacontext to use during design time.
<Window xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:MyNamespace" d:DataContext="{d:DesignInstance local:MainWindowViewModel}"> |
ViewModelBase
/// <summary> /// A method to wrap the INotifyPropertyChanged interface. /// </summary> public interface IViewModel : INotifyPropertyChanged { /// <summary> /// A method to wrap the call of the INotifyPropertyChanged.PropertyChanged event. /// </summary> /// <param name="propertyName">The name of the property which changed.</param> void OnPropertyChanged(string propertyName); } /// <summary> /// An implementation of a basis ViewModel with a useful method OnPropertyChanged /// to warn that a property has changed. /// </summary> public class ViewModelBase : IViewModel { /// <summary> /// A method to wrap the call of the PropertyChanged event. /// </summary> /// <param name="propertyName">The name of the property which changed.</param> public void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } /// <summary> /// Se produit lorsqu'une valeur de propriété est modifiée. /// </summary> public event PropertyChangedEventHandler PropertyChanged; } |
RelayCommand
ViewModel first
En fonction du type de vue-modèle, le DataTemplate permet de choisir la vue.
<Window.Resources> <DataTemplate DataType="{x:Type ViewModel1}"> <View1 /> </DataTemplate> <DataTemplate DataType="{x:Type ViewModel2}"> <View2 /> </DataTemplate> </Window.Resources> <!-- en fonction du type passé à CurrentViewModel (ViewModel1 ou ViewModel2) un DataTemplate (une vue) sera appliqué aux données de CurrentViewModel (respectivement View1 ou View2) --> <ContentControl Content="{Binding CurrentViewModel}"></ContentControl> |
public class MainWindowViewModel { public object CurrentViewModel { get; set; } } |
Refactoriser du code pour MVVM
- Rendre le Model Observable (INotifyPropertyChanged)
- Créer un ViewModel
- EventHandler → Command ou Behavior
- Injecter le DataService
- Injecter les ViewServices (DisplayMessage, Navigation)
- Binder View et ViewModel
- Ajouter des Design Time Data
- DesignDataService : IDataService
- Créer des Unit Tests: simuler (Mock) les services
- TestDataService : IDataService
- ViewService : IViewService