Affichage des articles dont le libellé est MVVM. Afficher tous les articles
Affichage des articles dont le libellé est MVVM. Afficher tous les articles

WPF Modern UI Comparative Architectures

Je cherche à découvrir les structures (ou les architectures) des applications WPF, j'ai découvert plusieurs Templates d'applications WPF avec des Galeries de Composants Graphiques Utilisateurs et je vois beaucoup de code derrière alors à quoi sert-il, pourquoi tout ce code ?

Je zoom sur Wpf.UI du projet :

GitHub WPF-UI Lepo.co

WPF-UI se trouve en package nuget téléchargeable indépendamment : 

NuGet Gallery | WPF-UI 2.0.3

Pour la Librairie WPF-UI utilisée en référence dans le projet :

\Lepoco-WpfUI\src\Wpf.Ui.Gallery\Wpf.Ui.Gallery.csproj

On trouve la structure suivante :

Lepo Wpf.UI - Structure
Lepo Wpf.UI - Structure

La seule dépendance de Wpf.Ui en dehors du framework c'est : System.Drawing.Common

Microsoft Learn - System.Drawing.Common .NET

En essayant de comparer la structure de cette application WPF avec le projet :

GitHub-Kinnara - ModernWpf

Qui lui ne fait aucune référence à System.Drawing.Common...

Je vais utiliser un troisième modèle de comparaison car Kinnara me semble ne pas utiliser les structures nécessaires pour utiliser le modèle MvvM qui est acquis maintenant.

Et la base de tous certainement :

GitHub - MahApps

On ne conçoit pas de développer une application conséquente sans structuration par MvvM, injection des dépendances, ... aussi je me lance dans un premier template :

GitHub-mabyre/WpfAppRibbonTemplateStudio

A partir de TemplateStudio le modèle Ribbon - Prism

Il me semble qu'en démarrant directement un projet à l'aide de TemplateStudio, je passe à côté de nombreuses problématiques, du coup je vais décrire les Samples des projets que j'ai déjà récoltés. Afin d'en découvrir la structure.

A force de me promener dans ces différents projets, je trouve un truc que je crois être cool, pour traiter les icônes dans : 

\\Visual Studio 2022\Samples\Kinnara-ModernWPF\ModernWPF Net6-7\ModernWPF\ModernWpf\IconElement\Symbol.cs

Mais cela va me mener encore plus bas dans l'OS MS... dans le traitement des icônes.

Les projets de Modern UI pour WPF ont tous une grosse librairie associée dont voici une description succincte des dépendances afin de mieux saisir comment elles sont imbriqués dans l'OS MS ou framework :

Fluent.Ribbon

System.Windows.Documents.Adorner

System.Windows.FrameworkElement

System.Windows.DependencyObject

System.Windows.DependencyProperty

System.ComponentModel.INotifyPropertyChanged

System.Windows.Automation.Peers.FrameworkElementAutomationPeer

System.Collections.ObjectModel.ObservableCollection

System.Windows.Controls.ItemsControl

System.Windows.RoutedEventArgs : EventArgs

System.Windows.Data.IValueConverter

System.Windows.Data.IMultiValueConverter

MahApps.Metro

System.Windows.FrameworkElement

Microsoft.Xaml.Behaviors.TriggerAction<T>

Microsoft.Xaml.Behaviors.Behavior<T>

ControlzEx.Behaviors.WindowChromeBehavior

System.Windows.DependencyObject

System.Window.VisualStateManager : DependencyObject 

System.Windows.DependencyProperty

System.Windows.Automation.Peers.FrameworkElementAutomationPeer

System.Windows.Point

System.Windows.Controls.Primitives

System.Windows.FreezableCollection<T>

System.Windows.Controls.Control : FrameworkElement

System.IEquatable<T>

System.Windows.Controls.ContentControl

System.Windows.Controls.HeaderedContentControl : ContentControl

System.Windows.RoutedEventArgs : EventArgs

System.Resources.ResourceManager

System.Windows.Data.IValueConverter

System.Windows.Markup.MarkupExtension

Wpf.Ui Lepo

System.Windows.Input.ICommand

System.Action<T?> 

System.PlatformID

System.Windows.Controls.ContentControl

System.Windows.Clipboard

System.Windows.RoutedEventHandler

System.Windows.RoutedEvent

System.Windows.DependencyProperty

System.Drawing.ToolboxBitmap

System.Windows.Window

System.Windows.Interop.WindowInteropHelper

System.Windows.Data.IValueConverter

System.Windows.Data.IMultiValueConverter

System.Windows.SystemParameters

System.Windows.Point

System.Windows.Media.RenderCapability

System.Runtime.InteropServices

System.Windows.Interop

La partie de la Lib Wpf.Ui concernant l'Interop (interopérabilité) est instructive je vous la conseil

System.Windows.ResourceDictionary

System.ComponentModel

System.Windows.Markup

System.Windows.DynamicResourceExtension

ModernWPF by Kinnara

Cette Librairie modern WPF semble prendre ses racines encore plus loin dans l'OS MS. Voici donc quelques références loin loin dans le framework MS.

Je note ici les dépendances qui ne sont pas dans les autres projets (ou que je n'ai pas trouvé).

System.WeakReference<T> : ISerializable where T : class (allow object to control its own serial/deserial)

System.Resources.ResourceManager gestion de la localization

TypedEventHandler<TSender, TResult>(TSender sender, TResult args)

System.Windows.Freezable : DependencyObject

System.Windows.Media.Geometry

System.Windows.Controls.ContentPresenter : FrameworkElement

System.Windows.CornerRadius : IEquatable<CornerRadius>

...

Dépendances des Librairies Modern UI

C'est un travail fastidieux mais il permet de rendre compte de l'imbrication de ces librairies avec le framework (ou les frameworks .NET Framework 4.6.2 - 4.7 .NET Core 3.1). 

Des trois librairies Wpf.Ui est un peu différentes car elle ne s’appuie que sur le framework .NET 6.0. mais Wpf.Ui descend très profondément dans la tripaille de Windows, avec des objets comme Interop et InterropServices qui sont bas dans l'OS et en redéfinissant par exemple le "Point".

Fluent.Ribbon est la plus simple des trois librairies c'est certainement lié au fait qu'elle ne se préoccupe que de l'objet Ribbon.

On peut constater que les ModernWpfUI ont encore besoin de beaucoup de code pour fonctionner.

WPF Modern Application - Structure

A ce stade, il est important de faire la liste des sujets que l'on va aborder Ici. Car petit à petit en progressant, je me rends compte qu'ils sont nombreux. Les différentes documentation sont pléthoriques.

Donc quels sont les grands sujets concernant l'architecture des applications WPF ? 

Microsoft Learn - Vue d’ensemble des bibliothèques runtime

Cette page nous propose les sujets de structuration de votre application WPF suivants :

Contenu conceptuelPackage NuGet
ConfigurationMicrosoft.Extensions.Configuration
Injection de dépendances    Microsoft.Extensions.DependencyInjection
Globbing de fichiersMicrosoft.Extensions.FileSystemGlobbing
Hôte génériqueMicrosoft.Extensions.Hosting
HTTPMicrosoft.Extensions.Http
LocalisationMicrosoft.Extensions.Localization
LoggingMicrosoft.Extensions.Logging

Voilà déjà une liste des sujets proposés par Microsoft Learn.

Démarrage

Navigation

MVVM

WPF Modern Application - Démarrage & Navigation

Le démarrage d'une application WPF dépend des choix concernant la Navigation entre les Page, Windows ou UserControl.

La Navigation est le premier Sujet d'une application WPF.

Stack Overflow -Window vs Page vs UserControl for WPF navigation ?

Les trois objets de la Navigation sont :

  • Window quand vous souhaitez faire apparaître une nouvelle fenêtre
  • Page qui est à l'intérieur d'une fenêtre plutôt utilisée dans les systèmes à base de Web comme XBAP
  • UserControl qui contient des contrôles créés dynamiquement comme lorsque l'on utilise le pattern MVVM

Avec Prism les ViewModel dérivent de BindableBase 

avec Community.Mvvm ils dérivent de ObservableObject.

Les deux Modèles Prism et Community.Mvvm sont assez différents, il y a bon nombre de lignes de code qui diffèrent.

Fluent.Ribbon - Showcase

App.xaml : StartupUri="TestWindow.xaml"

App.xaml.cs : Gestion des Theme par ControlzEx

Button Click="OpenRibbonWindowColorized_OnClick"

private void OpenRibbonWindowColorized_OnClick(object sender, RoutedEventArgs e)
{
      new RibbonWindowColorized().Show();
}

MahApps.Metro - Demo

App.xaml : StartupUri="MainWindow.xaml"

MainWindow.xaml.cs : 

    public partial class MainWindow : MetroWindow : Window PART_Icon, PART_TitleBar
    {
        public MainWindow()
        {
            _viewModel = new MainWindowViewModel(DialogCoordinator.Instance);
            DataContext = _viewModel;

    public class MainWindowViewModel : ViewModelBase, IDataErrorInfo, IDisposable
    {
            this.Title = "Flyout Binding Test";
            this._dialogCoordinator = dialogCoordinator;
            SampleData.Seed();

Focus sur le bouton du menu : "Show InputDialog"

MahApps.Metro.Samples\MahApps.Metro.Demo\MainWindow.xaml

     <MenuItem Click="ShowInputDialog" Header="Show InputDialog" />

\MahApps.Metro.Samples\MahApps.Metro.Demo\MainWindow.xaml.cs

        private async void ShowInputDialog(object sender, RoutedEventArgs e)
        {
            var result = await this.ShowInputAsync("Hello!", "What is your name?");

            if (result == null) //user pressed cancel
                return;

            await this.ShowMessageAsync("Hello", "Hello " + result + "!");
        }

Vu comment cela est architecturé, on aurait du mal à passer le résultat de ces boites de dialogues dans le ViewModel de la fenêtre principale...

ModernWPF by Kinnara

Rien dans App.xaml.cs, App.xml fait un StartupUri="MainWindow.xaml" et pour la Navigation ils utilisent public partial class NavigationRootPage :

 \ModernWpf.SampleApp\Navigation\NavigationRootPage.xaml.cs

public class partial NavigationRootPage

Wpf.Ui Lepo

Dans Wpf.Ui.Demo.Mvvm l'application démarre grâce à Microsoft.Extensions.Hosting :

\\Lepoco-WpfUI\src\Wpf.Ui.Gallery\App.xaml.cs

https://docs.microsoft.com/dotnet/core/extensions/generic-host
https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
https://docs.microsoft.com/dotnet/core/extensions/configuration
https://docs.microsoft.com/dotnet/core/extensions/logging

Le parti pris de Lepo Wpf.UI est de ne pas utiliser Prism et cela va nous permettre de comparer les différentes architectures.

Là on est au cœur de la structuration ou architecture des applications Microsoft .NET.

Le début de la documentation concernant l'architecture des applications WPF :

Microsoft Learn - Vue d’ensemble des bibliothèques runtime

Avec Prism on a des UserControl avec CommunityToolkit.Mvvm Page

Prism UserControl vs CommunityToolkit.Mvvm Page

La Navigation est le premier sujet Wpf.Ui Lepo propose déjà trois Templates avec des modes de navigation, MS Store, Fluent et Compact...

Curieusement les trois Templates sont tout à fait équivalents aucun avec Prism.

TemplateStudio

La Navigation avec Prims semble plus simple, plus intégrée, le répertoire Services est moins rempli.

Configuration

Microsoft.Extensions.Hosting est remplacé par Prism.IoC.IContainerregistry.

To Be Continued...

Quel Template de modern UI pour WPF ?

Je viens de passer du temps avec Microsoft Template Studio qui installe un Template de modern UI autour de MahApps.Metro pour WPF avec plein d'autres fonctionnalités.

Alors existe t-il d'autres templates de modern UI pour WPF ? 

WPF modern UI Frounisseurs

Dans WPF, comme fournisseurs d'UI moderne et composants graphiques, on retrouve classiquement :

Telerik.com

Infragistics/products/WPF

DevExpress

...

WPF modern UI Gratuits

On va essayer de trouver quelques bons projets de WPF Modern UI. Pour l'instant pas de classement mais une découverte rapide des différentes solutions qui nous sont proposées.

Kiranna ModernWPF

GitHub - Kinnara/ModernWpf

Kinnara/ModernWpf est un travail très intéressant et très important, autour des pacakges UI dédiés à WPF. Il part du framework de base Microsoft.WindowsDesktop.App.WPF pour réaliser une application complète de contrôles utilisateur AutomationPeer.

Un de ses projets utilise (est dépendant de) le package MahApps.Metro mais pas les autres.

Une série de Samples démontrent l'utilisation de Fluent.Ribbon, Dragablz, FluentWPF, MahApps.Metro.

\\Visual Studio 2022\Samples\Kinnara-ModernWPF\ModernWPF Net6-7\ModernWPF\ModernWpf.SampleApp\ModernWpf.SampleApp.csproj

Voici un exemple de la Gallery :

WPF UI - ModernWpf.SampleApp
WPF UI - ModernWpf.SampleApp

Intégration du Package MahMetro :

\\Visual Studio 2022\Samples\Kinnara-ModernWPF\ModernWPF Net6-7\ModernWPF\samples\MahAppsSample\MahAppsSample.csproj

ModernWPF- MahAppsSample
ModernWPF- MahAppsSample

Une véritable mine d'or pour ceux qui souhaitent maîtriser WPF UI la plus part des ressources viennent de MahApps mais pas seulement.

If you need the ModernWpf from Yimeng Wu for .NET 6.0 or .NET 7.0 It's here in Discussion Tab :

GitHub - Kinnara/ModernWpf - Discussion #513 Net 6 and Net 7

Un travail très intéressant d'évolution de la solution vers .NET 6.0 et .NET 7.0 qui donne une idée du travail à effectuer pour migrer une application depuis les anciens frameworks vers .NET 6.0.

MahApps.Metro

C'est le projet utilisé par Microsoft TemplateStudio pour WPF et d'autres ...

Github - MahApps/MahApps.Metro

Pour l'instant, je n'arrive pas encore à exécuter ce projet sur ma plateforme de développement à cause d'une référence au framework 4.7 ... que je ne souhaite pas installer, bref... je prends le code de release :

https://github.com/MahApps/MahApps.Metro/releases 2.4.9, je supprime "net47" dans les propriétés des projets et ça fonctionne : 

MahMapps.Metro elegant WPF UI

Vous pouvez trouver la structure des NuGets MahApps.Metro dans le projet :

https://github.com/MahApps/MahApps.Metro/wiki/Visual-Studio-Templates

Pour démarrer rapidement avec MahApps.Metro c'est ici :

MahApps - Guides Quick-start - Installation

Mais alors vous démarrez tout en bas, avec un NutGet et le Guide pour créer votre première page MetroWindow :

Install Nuget MahApps.Metro
Install Nuget MahApps.Metro for WPF solution

Mais croyez moi il du chemin à faire pour obtenir une application WPF digne de ce nom.

Fluent.Ribbon

C'est le projet de Base a utiliser, si vous souhaitez développer une application WPF autour d'un "Ribbon" un Ribbon est bien plus qu'un ruban, c'est un menu Windows Office Like c'est donc un menu extrêmement efficace pour lancer tout un tas de commandes depuis ce Ribbon.

Github -Fluent.Ribbon.Showcase

Voici l'interface UI du projet Fluent.Ribbon exécutée par Visual Studio 2022 Community :

Fluent.Ribbon WPF UI
Fluent.Ribbon WPF UI

Le problème étant que ce Ribbon est très "Windows Like" aujourd'hui on préférera des menus plus simples.

Mais ce projet est une mine d'or pour les développeurs WPF car il met en oeuvre un nombre incalculable de techniques pour développer une belle UI pratique.

WPF UI Fluent Modern Lepo

WpfUI/lepo

GitHub - lepoco - wpfui

C'est dans la même vaine, un projet très complet avec Extension, Template d'application WPF.

Open source dans le GitHub, respect des licences :

https://github.com/lepoco/wpfui/tree/main/src/Wpf.Ui

Quel model MvvM ? WPF UI Lepoco n'utilise pas Prism c'est le CommunityToolkit.Mvvm

De très intéressants Scripts dans le répertoire :

https://github.com/lepoco/wpfui/tree/main/scripts

Si vous souhaitez exécuter la Solution Wpf.Ui.Demo avec Visual Studio 2022 et .NET 6.0, il vous suffit de supprimer les références aux frameworks ;netcoreapp3.1;net48;net472;net462

Dans le fichier : /Wpf.Ui/Wpf.Ui.csproj :

<TargetFrameworks>net7.0-windows;net6.0-windows;netcoreapp3.1;net48;net472;net462</TargetFrameworks>

Exécution du projet Wpf.Ui.Demo.Mvvm.csproj :

Modern UI WPF Lepoco - Wpf.Ui.Demo.sln
Modern UI WPF Lepoco - Wpf.Ui.Demo.sln

Exécution du projet Wpf.Ui.Gallery.sln :

ModernWPF UI Leco.co Gallery
ModernWPF UI Leco.co Gallery

C'est un projet extrêmement impressionnant avec une quantité de codes source gigantesque pour faire fonctionner tout cela.

J'ai installé l'extension WPF UI :

https://marketplace.visualstudio.com/items?itemName=lepo.wpf-ui

Dans Visual Studio 2022 :

WPF UI lepo.co
WPF UI lepo.co

C'est vraiment très complet, voici la structure du Template d'Application : 

WPF UI Lepo.co
WPF UI Lepo.co

On a vraiment un très beau et très complets Template d'application WPF.

Adonis UI

Adonis UI/Lightweight UI toolkit for WPF

benruehl/adonis-ui: Lightweight UI toolkit for WPF applications offering classic but enhanced windows visuals

Semble prometteur tout en bas de la page une Demo à télécharger.

To Be Continued...

WPF Modern UI - Conclusion

Me voilà avec des tonne de code sources d'exemples pour créer mon application WPF.

Je vais continuer de cherche d'autres exemples de Modern UI Template mais je peux déjà dire que j'ai atteins mon objectif, consolider mes connaissances en développement d'applications WPF modernes. Il y a du chemin de parcouru par les communautés ... depuis silverlight ;-))

Je vais également étudier de plus prêt tout le code fournit avec ces exemples de Modern UI for WPF pour en décrire la structure ou l'architecture Navigation, Configuration, MvvM, etc.

A la découverte de Microsoft Template Studio for WPF

Quels sont les sujets abordés et résolut par le TemplateStudio en WPF ? C'est la question que je vais me poser ce matin.

Je choisi un projet type ribbon prism et WPF, et je me rends compte que le Ribbon ne fonctionne pas, du moins, il est vide. C'est le côté didactique de Template Studio, il faut le remplir selon la page d'aide suivante :

Github - Microsof - TemplateStudio - WPF- ribbon

Mais je me suis fait avoir pas cette page qui implémente le Fluent.Button dans ListDetailsPage.xaml tandis que, ce que l'on souhaite faire, c'est créer un bouton dans le Ribbon qui permette d'afficher la page ListDetailsPage.xaml et les autres pages choisies dans le Wizard du TemplateSutdio.

Il faut donc implanter le Fluent.Button dans ShellWindow.xaml et la ICommand dans ShellViexModel.cs. 

Ce qui donne le résultat suivant :

TemplateStudio for WPF with Ribbon button implemented
TemplateStudio for WPF with Ribbon button implemented

Ceci fait, j'aimerais avoir des icônes pour les boutons des autres pages et je suppose que l'on peut par exemple récupérer les icônes du Template Navigation Pane qui sont dans :

GitHub - MahApps.Metro framework that allows a better UI for their own WPF

Comme indiqué dans :

GitHub - TemplateStudio - WPF - navigationpane

MahApps.Metro est un vaste sujet. On aura remarqué que dans notre Template WPF la ShellWindow est une MetroWindow.

Je cherche maintenant à intégrer des Icones dans mon Ribbon pour afficher les autres images pages que j'ai choisies dans mon wizard de TemplateStudio.

La navigation dans TemplateStudio WPF NavigationPane se fait par un : HamburgerMenu

<controls:HamburgerMenu
    ItemsSource="{Binding MenuItems}"
    ItemCommand="{Binding MenuItemInvokedCommand}"

Dont la propriété ItemSource est bindée sur une magnifique ObservableCollection :

    public ObservableCollection<HamburgerMenuItem> MenuItems { get; } = new ObservableCollection<HamburgerMenuItem>()
    {
        new HamburgerMenuGlyphItem() { Label = Resources.ShellMainPage, Glyph = "\uE8A5", Tag = PageKeys.Main },
        new HamburgerMenuGlyphItem() { Label = Resources.ShellListDetailsPage, Glyph = "\uE90C", Tag = PageKeys.ListDetails },
        new HamburgerMenuGlyphItem() { Label = Resources.ShellContentGridPage, Glyph = "\uE774", Tag = PageKeys.ContentGrid },
        new HamburgerMenuGlyphItem() { Label = Resources.ShellDataGridPage, Glyph = "\uE707", Tag = PageKeys.DataGrid },
    };

On pourrait faire de même pour le modèle ribbon mais ! On a du mal à implanter une iconPacks dans le Fluent:Button d'un Fluent:RibbonGroupBox :

<Fluent:RibbonGroupBox
                        State="Large"
                        MinWidth="150"
                        Header="GroupBox 1">
                        <!--_BRY_ NE MARCHE PAS-->
                        <Fluent:Button
                            Size="Large"
                            Command="{Binding OptionsMenuItemInvokedCommand}">
                            <iconPacks:PackIconControl Kind="{x:Static iconPacks:PackIconMaterialKind.AccessPoint}"
                                   Width="48"
                                   Height="48" />
                        </Fluent:Button>
                    </Fluent:RibbonGroupBox>

Ce la ne fonctionne pas ! Les propriétés de l'objet Fluent:Button ne le permettent pas.

Fluent.Ribbon pour Template Studio 

Allons voir chez Fluent.Ribbon ce que nous avons :

GitHub - Fluent.Ribbon: WPF Ribbon control like in Office

Étonnant ce GitHub, cela fait deux fois que je vois une documentation propre sur un site dédié mais abandonnée tandis que la documentation du projet se poursuit dans le GitHub.

Alors avec Fluent.Ribbon, il on essayé GitHub Pages & Jekyll pour la documentation... 

Fluent.Ribbon.github.io

Moi aussi :

My site with Github Pages & Jekyll | Mabyre’s page

Le problème du ShowCase de Fluent.Ribbon, c'est qu'il faut installer un tas de vieux trucs dont on aura pas besoin :

Sur ma plate forme actuelle Visual Studio 2022 .NET 6.0 :

Installations à effectuer pour travailler avec le ShowCase de Fluent.Ribbon
Installations à effectuer pour travailler avec le ShowCase de Fluent.Ribbon

Sur mon bon vieux Visual Studio 2019 .NET Framework 4.8

Installations à effectuer pour travailler avec le ShowCase de Fluent.Ribbon

Franchement, je vais vous dire, je ne suis pas chaud...

D'autant que la version 10.0 va bientôt sortir :

Github - Milestones - Fluent.Ribbon

Il est urgent d'attendre... la prochaine Mise à jour de Fluent Ribbon pour l'essayer avec le dernier Visual Studio 2022 et le .NET 6.0.

WPF Prism Ribbon TemplateStudio on GitHub

Pour développé un Template Studio Project WPF ayant fait le choix dans le Template Studio Wizard, de la Navigation avec Ribbon, du Framework Prism pour le côté MvvM et plus, avec en plus quelques pages d'essais et des exemples, voici mon projet dans le GitHub :

GitHub - mabyre/WpfAppRibbonTemplateStudio

Nous pourrons ainsi parfaire nos connaissances.

N'hésitez pas à partager et à liker, à venir dans le github mettre une petite étoile.





























WPF Template Studio for Visual Studio

Voilà, j'ai installé Visual Studio 2022, je peux installer l'extension Template Studio for WPF et créer quelques templates d'applications WPF pour en apprendre la structure de ce type d'application Microsot .NET :

Template Studio for WPF

A noter que Template Studio existe pour les technologies Microsoft UWP, WPF et WinUI. Ici je me focalise sur WPF.

Installer l'extension pour Visual Studio :

Visual Studio Marketplace - Template Studio for WPF

Voici le GitHub de Template Studio :

GitHub-Microsoft-Template Studio creation of new WinUI 3, WPF, and UWP apps using wizard

Et la page de documentation dédiée à WPF :

Template Studio - getting-started-endusers.md at main

Là on est au cœur du sujet, au cœur de développement des applications modernes avec WPF. Dans ce template le wizard permet de choisir un Design Patterns :

Prism : qui est plus qu'MvvM mais permet de faire de l'IoC de suivre les Design Pattern et de faire de grandes applications modulables et scalables

MVVM Toolkit : The CommunityToolkit.Mvvm package is a modern, fast, and modular MVVM library.

MVVM Basic

MVVM Light Toolkit : by Laurent Bugnion (le fameux Laurent Bugnion mais dont le framework s'éteind un peu avec Visual Studio 2017...

Mais Laurent Bugnion continue d'inspiré la communauté et son travail se retrouve maintenant dans :

GitHub - CommunityToolkit.MvvM - Samples

Avec une belle page d'explication sur le modèle MVVM :

Microsoft Learn - Présentation du kit de ressources MVVM - .NET Community Toolkit

De nombreuses autres possibilités s'offrent à nous pour créer le template de l'application WPF parfaite. C'est une avancée majeur pour les débutants dans l'appréhension de la structure d'une application WPF.

Je dirais c'est pas trop tôt !

Structure du template WPF

Quels sont le contrôles utilisés ? Comment faire évoluer mon Template WPF de base.

On est avec MahMetro :

GitHub - MahApps.Metro: Framework allows developers to cobble together a better UI for their own WPF applications with minimal effort

using MahApps.Metro.Controls;

namespace WpfApplication

  public partial class MainWindow : MetroWindow
 { 
     public MainWindow()
    {
        InitializeComponent();
    }
 }

...

Ma MainWindows est une MetroWindow ...

Template Studio WPF Services - Forced Login

L'instanciation puis l'exécution de ce type d'application WPF créé une erreur car vous devez faire un certains nombre de choses avant de pouvoir exécuter cette application.

Créer un Client ID

Regardez dans la fenêtre "Liste des tâches" ou TODO List de votre Visual Studio. Vous devez entre autre créer un Application client ID : 

Dans votre Portail Azure (et si vous n'en avez pas créer un compte Azure...) vous avez la possibilité de créer un IdentityClientId pour votre application un ID d'application Client :

Azure -> Azure Active Directory -> Inscription d'application -> "+ Nouvelle inscription".

Vous obtenez ainsi un UID (Unique) d'application client que vous reportez dans votre code dans le fichier :

\\Visual Studio 2022\Templates\TemplateStudio\App-0\App1\appsettings.json :

{
  "AppConfig": {
    "userFileName": "User.json",
    "identityClientId": "xxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxxx",
    "identityCacheFileName": ".msalcache.dat",

Voilà vous pouvez maintenant exécuter votre template d'application WPF avec Forced Login.

Project Type - Navigation Pane

C'est une application "moderne" avec un Hamburger Menu, c'est cool mais en exécutant l'application :

Template Studio - Navigation Pane - Hamburger Menu
Template Studio - Navigation Pane - Hamburger Menu

Les Icônes des Items sont toutes les même... Grrr... Je regarde un peu dans la documentation :

Github - Template Studio - navigationpane.md

C'est cool :

Template Studio - Navigation Pane - Hamburger Menu

Voilà on vient de voir, comment démarrer rapidement avec le Template Studio for WPF.

Ce que je vais faire maintenant, c'est regarder pourquoi le Ribbon project avec Fluent Ribbon n'affiche pas les Pages...

En suite, je choisirai un project template idéal sans doute avec Prism et j'essayerai d'ajouter une page.

N'hésitez pas à commenter, à partager...

Où en est-on du Design Pattern MVVM en WPF ?

Pour réaliser une application WPF sur le modèle MVVM que dois-je faire aujourd'hui en 2019 ? J'en suis resté à quelque chose de pas très fini ni tout à fait utilisable à mon sens. 

Nous avons chacun un petit bout de MVVM Design Pattern implémenté à sa sauce, je cite pelle mêle, Laurent Bugnion,  Josh Smith (who thanks John Gossman), Prism, Wilfried Woiré, Alexy Shelest ...

J'ai également contribué à l'époque avec le GitHub - WPF Prims Toolkit.

Avec Prims ou pas Prism avec MEF ou pas MEF ...

Pour accéder à la librairie PRISM :

http://prismlibrary.github.io
Cette image vient de PRISM

Alors, je reprends les reines et j'espère bien qu'aujourd'hui, si j'instancie une nouvelle Application Desktop WPF avec mon Visual Studio 2017 Community le framework design pattern MVVM est déjà dans mon Template d'application WPF. Non ?

Malheureusement, je replonge dans les affres d'MVVM avec des sites actuels qui m'expliquent ce qu'est le modèle M-V-VM :

C# Corner - MVVM in WPF

Nipun Tomar présente le Design Pattern MVVM comme si c'était un truc nouveau le "last update" de son article date de Fev 2018 ! Alors qu'en bas (conseil pour connaitre la vraie date d'un article allez voir les commentaires) les commentaires dates de 2013. On est où ? En 2018 ou en 2013 ? 

Bon, j'avoue les explications sont vraiment très bonnes et très complètes sur la comparaison des modèles MPV, MVC et MVVM, si vous ne connaissez pas MVVM ça peut bon à prendre.

Pour le reste, je dois retourné avec Laurent Bugion et la chose principale qui a changée depuis lors c'est la disparition du CodePlex snif ! Laurent Bugnion a migré son projet dans GitHub :

GitHub - Laurent Bugnion - mvvmlight

C'est bien parce qu'il existe encore et malgré tout, cela permet de voir que la communauté est vivante. Mais son framwork est orienté portabilité Xamarin.Android, Xamarin.iOS, Xamarin.Forms, WPF. C'est curieux il cite encore Silverlight :-))

Et à part ça ?

SupInfo - WPF - MVVM : Le Data Binding (lien supprimé devenu payant sans doute)

Ils sont mignons, aucun code, tout à la mimine, depuis zéro, en Oct. 2015 ! Et bien ils ne sont pas en avance.

Et donc, en continuant mes recherches, je retrouve également Prism et son nouveau site ... avec peut-être en roadmap la version 6.0.

http://prismlibrary.github.io/docs/wpf/legacy/Implementing-MVVM.html
Prism Library - Implementing the MVVM Pattern Using the Prism Library for WPF

Voilà, alors faut-il aller plus loin ? Je pense qu'il me faut commencer par installer un Template. C'est tout en bas de la page :

https://marketplace.visualstudio.com/items?itemName=BrianLagunas.PrismTemplatePack
Prism Template Pack

Ce n'est pas un NuGet mais une extension Visual Studio :

Visual Studio -> Outils -> Extensions et mises à jour ...

Je n'ai pas trouvé si facilement, j'ai du aller dans -> En ligne -> Visual Studio Marketplace -> Modèles -> Visual C# -> WPF et dans la barre de recherche je tape "Prism" :

Extension Visual Studio - Prism

Voilà, je vais tester tout ça te revenir vous dire si on peut faire une Application Desktop WPF efficace avec tout ça.

Il y a un nom a retenir c'est Brian Lagunas qui est le "product owner" de Prism 6.0 qui sortira surement bientôt ;) et qui est totalement "Open Source".

Pour faire fonctionner quelques exemples comme :

GitHub - Brian Lagunas - InfragisticsWebinarSimpleMVVMPrism

L'installation du Prism Template Pack n'a pas suffit. J'ai du exécuter la commande suivante dans la Console du Gestionnaire de package :

PM> Install-Package System.Windows.Interactivity.WPF -Version 2.0.20525

Pour la suite je me permets de noter un autre lien :

GitHub - PrismLibrary / Prism

Have fun!

Objets MVVM

Quels sont les objets MVVM nécessaires à l'exécution des applications C# .NET basées sur le Modèle M-V-VM ?

Objets dérivés de l'interface ICommand
RelayCommand
DelagateCommand
DelegateCommandWithParam

Objets dérivés de INotifyPropertyChanged
ObservableObject

PropertyObserver

Autres objets
EventToCommand
Mediator
Messenger

ViewModelBase : INotifyPropertyChanged

View modèles de base
ViewModelBase : peut dériver de DependencyObject
Tous les ViewModel vont dériver de ViewModelBase

Controler de base

WPF Drag & Drop in Grid Sample

Drag and Drop, ce n'est peut être pas si facile. Bien souvent il manque quelques astuces de bases comme par exemple quand on Drop dans une Grid on aimerait bien savoir dans quelle cellule on a dropé l'objet.

Alors on part de l'exemple MSDN :

Drag and Drop on a user control

MSDN Drag and Drop Sample

On écrit une couleur dans le TextBox et en la dropant  dans un des cercles on change la couleur du cercle, on peut copier un cercle en le dropant en maintenant la touche contrôle appuyée.

C'est intéressant mais il nous manque tout un tas de choses. Ce que j'aimerais faire c'est dropper des objets dans une Grid savoir où il sont dans la Grid et pouvoir commencer réellement à jouer avec mes objets.

Il est par exemple intéressant de jouer avec les propriétés de ma Grid et d'y déplacer les objets :

Grid.SetRow(object,x), Grid.SetColumn, Grid.SetColumnSpan,Grid.SetRowSpan

Je sais maintenant déplacer mes objets dans la Grid mais où sont -ils ?

Grid.GetRow(object,x),  object.GetValue(Grid.RowProperty)

Et voilà que je peux commencer à jouer.

Mais je voudrais aller plus loin et pouvoir dropper mes objects mais qu'ils ne se chevauchent pas. Pouvoir leur donner la taille que je veux en la changeant dans un menu contextuel et toujours en évitant qu'ils ne se chevauchent.

Voilà l'exemple que je vous propose :

WPF Drag&Drop Sample CanDrop and CanResize

Vous trouverez dans le code source suivant, la création dynamique d'objets dans la grille pour détecter où les objets sont droppés. Et tout un tas d'autres astuces vous permettant de réellement bien commencer avec le Drap&Drop en WPF.

Requirements :
WPF .NET 4.0
Visual Studio 2010
Microsoft.Practices.Prism
Microsoft.Practices.Prism.Interactivity
Microsoft.Practices.Prism.UnityExtension
Microsoft.Practices.Prims.Unity

Download and Setup Prism Library 5.0 for WPF

Inutile de préciser que les packages nugets sont difficiles à installer en ce qui concerne Prism et ses différentes version, en constante modification de version de namespace... bref la résolution de vos problèmes passera peut être par l'exécution de la commande : 

PM> Install-Package CommonServiceLocator dans la "Console du gestionnaire de package" 

suivie de 

PM> Install-Package Prism.UnityExtensions -Version 4.1.0

Download Sample

Si vous souhaitez aller plus loin et notamment en fonctionnant avec le modèle MVVM, je vous recommande vivement les articles suivants :

Drag and Drop in WPF
Drag and Drop in WPF - Part II

Ce que j'apprécie vraiment dans ce Sample c'est la mise en place d'un "Adorner", une parure qui à travers  une Property DragAdornerTemplate liée à une DependencyProperty affiche une image en transparence lorsque l'on déplace les objets. Dans le Xaml de la façon suivante :

<ListBox dd:DragDrop.DragAdornerTemplate="{StaticResource PupilDragAdorner}">

Voilà je vous ai tout dis sur mes recherches en matière de Drag & Drop avec WPF. Si vous allez plus loi merci de nous faire part de vos avanceés.

Vous avez apprécié cet article, laissez un commentaire.

EventToCommand avec Prism (2)

Comment câbler une InvokeCommandAction avec un CommandParameter qui passe un MouseEventArgs afin de récupérer et d'afficher les coordonnées de la souris dans la View.

Dans EventToCommand avec Prism (1) on à déjà vu pas mal de choses sur ce sujet.

S'en est pas encore fini avec EventToCommand de Prism ? Et bien non... Je regarde les exemples de Laurent Bugnion notamment EventToCommand Sample et je réussi à câbler la plupart des RelayCommand sur des DelegateCommand par exemple de la façon suivante :

<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding SimpleCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>

Ou de la façon suivante pour le bouton qui récupère un texte en paramètre :

<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ParameterCommand1}"
CommandParameter="{Binding Text, ElementName=ParameterTextBox}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>


Mais lorsque j'aborde l'exemple de l’ellipse (magnifique exemple de GalaSoft) qui permet d'afficher dans l'interface graphique (View) les coordonnées de la souris c'est la catastrophe. Avec une InvokeCommandAction, il est impossible de Binder une propriété CommandParameter sur quoi que se soit qui pourrait passer en paramètre à la DelagateCommand les MouseEventArgs afin d'afficher les coordonnées de la souris.

Et bien ce n'est si étonnant que cela, si on en juge par la page Starting work on Prism 4.1 c'est prévu mais pas encore intégré !

Une autre discussion du CodePlex fait bien référence à l'InvokeCommandAction mais elle ne résout pas ce problème.

Et nous voilà reparti dans les tréfonds du Framework au moins au niveau de DependencyObject .

EventToCommand avec Prims ma solution

Ma solution consiste à récupérer le code de MVVMLight : EventToCommandVS10.cs et de l'intégrer dans mon projet. Je n'ai pas choix car je pense qu'aucune solution n'est encore proposée par Prism v4.1.

InvokeCommandAction de Prims.Interactivity

namespace Microsoft.Practices.Prism.Interactivity
{
    public class InvokeCommandAction : TriggerAction<UIElement>

EventToCommand de MVVMLight 

namespace GalaSoft.MvvmLight.Command
{
    public class EventToCommand : TriggerAction<DependencyObject>

On regardera au passage ce qui est réalisé avec PassEventArgsToCommand.

EventToCommand avec Prism Code Source

Vous vous souvenez surement, j'essaye d'intégrer rapidement les frameworks MVVM, afin de voir et comprendre ce qu'ils apportent de plus par rapport à Prism ou bien trouver ce qui est déjà dans Prism. J'ai donc créé un projet MvvmFramework pour intégrer ce qui n'est pas dans Prism. Ce framework me permet de faire fonctionner mon projet WPFPrimsToolKit.

Les références de mon UserControl :
xmlns:prism="http://www.codeplex.com/prism"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mvvm.i="clr-namespace:MvvmFramework.Interactivity;assembly=FrameworkMvvm"

Me permettent de câbler mon Ellipse de la façon suivante :
<Ellipse Fill="{Binding Brushes.Brush5}"
Stroke="Black"
Margin="10,8"
Grid.ColumnSpan="2"
Grid.Row="7">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove">
<mvvm.i:EventToCommand Command="{Binding MoveMouseCommand}" 
  PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Ellipse>

Et quand je positionne ma souris dans l'ellipse verte, j'obtiens le résultat suivant :

Les MouseCoords sont affichées grâce à EventToCommand : TriggerAction<DependencyObject>

Download Source Code

Et comme un peu de code source vaut mieux qu'un long discours :

Requirements :
Visual Studio 2010 C# 
WPFToolKit
Prism v4.1







EventToCommand avec Prism (1)

Comment réaliser l'EventToCommand Dans Prism ? Au préalable je regarde rapidement comment cela est-il réalisé dans nos MVVM Framework favoris ?

CinchV2

EventToCommandTrigger

<TextBlock Style="{StaticResource aboutTextBlockStyleLinks}"
  Text="Home Page [At Codeplex]">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<CinchV2:EventToCommandTrigger
Command="{Binding AboutViewEventToVMFiredCommand}"
CommandParameter="Home"/>
</i:EventTrigger>                      
</i:Interaction.Triggers>                  
</TextBlock>

public SimpleCommand<Object, EventToCommandArgs> AboutViewEventToVMFiredCommand { get; private set; }

AboutViewEventToVMFiredCommand = new SimpleCommand<Object, EventToCommandArgs>(ExecuteAboutViewEventToVMFiredCommand);
private void ExecuteAboutViewEventToVMFiredCommand(EventToCommandArgs args)
{
switch ((String)args.CommandParameter)
{
            case "Home":

CompletedAwareCommandTrigger

<Grid x:Name="mainGrid" >
<i:Interaction.Triggers>
<CinchV2:CompletedAwareCommandTrigger 
Command="{Binding ShowActionsCommandReversed}">
<ei:GoToStateAction StateName="ShowActionsState"/>
</CinchV2:CompletedAwareCommandTrigger>

<CinchV2:CompletedAwareCommandTrigger
Command="{Binding HideActionsCommandReversed}">
<ei:GoToStateAction StateName="HideActionsState"/>
</CinchV2:CompletedAwareCommandTrigger>

</i:Interaction.Triggers>

ShowActionsCommandReversed = new SimpleCommand<Object, Object>((input) => { });

<VisualState x:Name="ShowActionsState">
/// <summary>
/// Goto "ShowActionsState", which use the VisualStateManagerService
/// </summary>
private void ExecuteShowActionsCommand(Object args)
{
ShowActionsCommandReversed.Execute(null);
}

<VisualState x:Name="HideActionsState"/>

/// <summary>
/// Goto "HideActionsState", which use the VisualStateManagerService
/// </summary>
private void ExecuteHideActionsCommand(Object args)
{
HideActionsCommandReversed.Execute(null);
}

<Label FontFamily="Wingdings" Foreground="Black"
VerticalAlignment="Center" Margin="10,5,5,5"
VerticalContentAlignment="Center"
FontSize="20" FontWeight="Normal"
Content="þ">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<CinchV2:EventToCommandTrigger 
Command="{Binding ShowActionsCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>

ShowActionsCommand = new SimpleCommand<Object, Object>(ExecuteShowActionsCommand);

GalaSoft

EventToCommand

<Button Background="{Binding Brushes.Brush3}"
Margin="10"
Style="{StaticResource ButtonStyle}"
Content="Parameter Command (Hello)"
Grid.Row="4"
ToolTipService.ToolTip="Click to activate command">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding ParameterCommand2}"
CommandParameterValue="Hello" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

public RelayCommand<string> ParameterCommand2
{
get;
private set;
}

public MainViewModel()
{
            ParameterCommand2 = new RelayCommand<string>(p =>
            {
                Status = string.Format("Parameter command executed ({0})", p);
                LastUsedBrush = Brushes.Brush3;
            });

<Button Background="{Binding Brushes.Brush4}"
Margin="10"
Style="{StaticResource ButtonStyle}"
Content="&quot;Disablable&quot; Command"
Grid.Row="5"
ToolTipService.ToolTip="Click to activate command">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding DisablableCommand}"
CommandParameter="{Binding Text, ElementName=DisableCommandTextBox}"
MustToggleIsEnabled="{Binding IsChecked, ElementName=MustToggleCheckBox}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<cmd:EventToCommand Command="{Binding ResetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

public RelayCommand<string> DisablableCommand
{
get;
private set;
}

public MainViewModel()
{
DisablableCommand = new RelayCommand<string>(p =>
{
Status = string.Format("Disablable command executed ({0})", p);
LastUsedBrush = Brushes.Brush4;
},
p => p != "Hello");

Remarques sur les implémentations de EventToCommand

Dans Cinch la SimpleCommand prend toujours deux paramètres ce qui oblige à lui passer des NULL lorsqu'il n'y a pas de paramètres on verra que dans Prism on déclare deux type de DelagateCommand.

Chez GalaSoft l'utilisation des paramètres n'est pas franchement évidente à mon goût.

EventToCommand avec Prism

Et je trouve enfin une série d'exemples grâce à deux discussion au sein du CodePlex dans Microsoft  patterns & practices: Prism

WPF PRISM modular design
Les conseils de Damian Cherubini sur une application modulaire utilisant Entity Framework.

Display Child window WPF
Exemples réalisés par Damian Cherubini, les sources sont dans son SkyDrive :

<UserControl x:Class="HelloWorldModule.Views.SelectClientView"
                               xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding ChangeDetailCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>

InvokeCommandAction se trouve dans System.Windows.Interactivity.dll
namespace HelloWorldModule.ViewModels
{
    public class SelectClientViewModel : Notification, INotifyPropertyChanged, IPopupWindowActionAware, IRegionManagerAware
    {
        public SelectClientViewModel()
        {
            this.ChangeDetailCommand = new DelegateCommand(this.ChangeDetail);

Et c'est exactement ce que je cherchais à faire !
Dans Prism il ne s'agit donc pas de EventToCommand mais de InvokeCommandAction un grand merci à Damian Cherubini dont les exemples que vous trouverez également dans son SkyDrive sont une mine d'or.

Allez plus loin sur ce blog c'est Ici.