Site icon Blog ARC Optimizer

Utilisation de la boîte à outils MVVM dans les applications .net Maui

Utilisation de la boîte à outils MVVM dans les applications .net Maui


Découvrez la boîte à outils .NET MVVM, une bibliothèque moderne, rapide et modulaire que vous pouvez l’utiliser dans votre application .net Maui.

Dans cet article, nous explorerons le .NET MVVM Toolkit, une bibliothèque MVVM modulaire maintenue par Microsoft et une partie de la Fondation .NET, qui peut vous aider à accélérer vos développements basés sur MVVM d’une manière très rapide et facile. Commençons!

La boîte à outils MVVM est une bibliothèque moderne, rapide et modulaire que vous pouvez utiliser dans différents types de projets qui prennent en charge l’utilisation de MVVM, tels que .FILET, WPF, Winformsetc. Étant donné que sa surface de l’API est identique sur toutes ces plates-formes, il est parfait pour construire des bibliothèques partagées. Un autre grand avantage qu’il offre est que les types définis dans la bibliothèque sont couplés de manière lâche, vous ne pouvez donc utiliser que les API dont vous avez besoin.

.NET MAUI est un cadre multiplateforme où le modèle MVVM peut être utilisé, ce qui en fait un candidat idéal pour l’utilisation de la boîte à outils MVVM. Voyons comment dans les sections suivantes.

Examiner un projet avec une implémentation MVVM traditionnelle

Si vous avez travaillé avec .net Maui, vous avez probablement entendu dire que pour les propriétés d’un modèle de vue pour envoyer des notifications de mise à jour à l’interface graphique, vous devez implémenter le INotifyPropertyChanged interface. De plus, vous devez déclencher le PropertyChanged événement en cas de changement de propriétés.

Traduire cela en un exemple pratique, créons une application qui effectue une conversion de devises. Si vous souhaitez reproduire cet exercice, suivez ces étapes:

  1. Créez un projet .net Maui sans utiliser l’échantillon de contenu.
  2. Suivre guide d’installation Pour ajouter une interface utilisateur de Telerik Progress pour .Net Maui Contrôles.
  3. Créer une nouvelle classe appelée CurrencyConverterViewModel ou similaire, et remplacez son contenu par ce qui suit:
namespace MauiExchangeDemo.ViewModels
{
    public class CurrencyConverterViewModel : INotifyPropertyChanged
    {        
        private decimal amount;
        public decimal Amount
        {
            get => amount;
            set
            {
                if (amount != value)
                {
                    amount = value;
                    OnPropertyChanged(nameof(Amount));
                }
            }
        }

        private Currency selectedFromCurrency;
        public Currency SelectedFromCurrency
        {
            get => selectedFromCurrency;
            set
            {
                if (selectedFromCurrency != value)
                {
                    selectedFromCurrency = value;
                    OnPropertyChanged(nameof(SelectedFromCurrency));
                }
            }
        }

        private Currency selectedToCurrency;
        public Currency SelectedToCurrency
        {
            get => selectedToCurrency;
            set
            {
                if (selectedToCurrency != value)
                {
                    selectedToCurrency = value;
                    OnPropertyChanged(nameof(SelectedToCurrency));
                }
            }
        }

        private decimal result;
        public decimal Result
        {
            get => result;
            set
            {
                if (result != value)
                {
                    result = value;
                    OnPropertyChanged(nameof(Result));
                }
            }
        }
        
        public ObservableCollection<Currency> Currencies { get; set; }        

        public ICommand ConvertCommand { get; }

        public CurrencyConverterViewModel()
        {            
            Currencies = new ObservableCollection<Currency>
            {
                new Currency { Code = "USD", Rate = 1.0m },
                new Currency { Code = "EUR", Rate = 0.9m },
                new Currency { Code = "GBP", Rate = 0.8m },
                new Currency { Code = "JPY", Rate = 130.0m }
            };
            
            SelectedFromCurrency = Currencies[0];
            SelectedToCurrency = Currencies[1];

            ConvertCommand = new Command(ExecuteConvertCommand);
        }

        private void ExecuteConvertCommand()
        {
            if (SelectedFromCurrency == null || SelectedToCurrency == null)
                return;
            
            Result = Amount * (SelectedToCurrency.Rate / SelectedFromCurrency.Rate);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }        
    }

    public class Currency
    {
        public string Code { get; set; }
        public decimal Rate { get; set; }        
        public override string ToString() => Code;
    }
}
  1. Pour l’interface graphique, j’ai choisi d’utiliser des commandes Telerik, car la bibliothèque d’interface utilisateur comprend des contrôles non disponibles dans .NET MAUI, nous permettant de créer des interfaces mieux apparentées qui s’alignent avec nos objectifs. Remplacer le contenu de MainPage.xaml avec ce qui suit:
<ContentPage...>
    <ScrollView>
        <StackLayout Padding="30" Spacing="25">
            <Label
                FontAttributes="Bold"
                FontSize="28"
                HorizontalOptions="Center"
                Text="Currency Converter"
                TextColor="#2E3A59" />
            <Border
                Padding="15"
                BackgroundColor="#F0F0F0"
                StrokeShape="RoundRectangle 10"
                StrokeThickness="0">
                <StackLayout>
                    <Label
                        FontSize="16"
                        Text="Amount:"
                        TextColor="#333333" />
                    <telerik:RadNumericInput
                        x:Name="input"
                        HeightRequest="50"
                        Maximum="1000000"
                        Minimum="0"
                        Step="0.01"
                        Value="{Binding Amount, Mode=TwoWay}" />
                </StackLayout>
            </Border>
            <Border
                Padding="15"
                BackgroundColor="#F0F0F0"
                StrokeShape="RoundRectangle 10"
                StrokeThickness="0">
                <StackLayout Spacing="10">
                    <Label
                        FontSize="16"
                        Text="From:"
                        TextColor="#333333" />
                    <telerik:RadComboBox
                        HeightRequest="50"
                        ItemsSource="{Binding Currencies}"
                        SelectedItem="{Binding SelectedFromCurrency}" />
                </StackLayout>
            </Border>
            <Border
                Padding="15"
                BackgroundColor="#F0F0F0"
                StrokeShape="RoundRectangle 10"
                StrokeThickness="0">
                <StackLayout Spacing="10">
                    <Label
                        FontSize="16"
                        Text="To:"
                        TextColor="#333333" />
                    <telerik:RadComboBox
                        HeightRequest="50"
                        ItemsSource="{Binding Currencies}"
                        SelectedItem="{Binding SelectedToCurrency}" />
                </StackLayout>
            </Border>
            <telerik:RadButton
                BackgroundColor="#007ACC"
                Command="{Binding ConvertCommand}"
                CornerRadius="8"
                HeightRequest="50"
                Text="Convert"
                TextColor="White" />
            <Border
                Padding="15"
                BackgroundColor="#E8F5E9"
                StrokeShape="RoundRectangle 10"
                StrokeThickness="0">
                <StackLayout HorizontalOptions="Center">
                    <Label
                        FontAttributes="Bold"
                        FontSize="18"
                        Text="Result:"
                        TextColor="#388E3C" />
                    <Label
                        FontSize="22"
                        Text="{Binding Result, StringFormat='{}{0:N2}'}"
                        TextColor="#388E3C" />
                </StackLayout>
            </Border>
        </StackLayout>
    </ScrollView>
</ContentPage>

Dans le CurrencyConverterViewModel Classe, vous pouvez voir que la définition des propriétés occupe beaucoup d’espace, en plus d’être très répétitive. D’un autre côté, la définition des commandes implique la gestion ICommand éléments, de la création ICommand Propriétés pour les initialiser en pointant la méthode qui exécute l’action. Cela peut également devenir très répétitif si vous avez plus d’une commande sur votre page.

C’est dans ces types de cas où MVVM Toolkit nous aide à simplifier le code dans nos projets, ce qui nous permet de nous concentrer davantage sur la logique de l’application. L’exécution de l’application avec le code précédent nous donne le résultat suivant:

Installation de la boîte à outils MVVM dans le projet

Pour utiliser la boîte à outils MVVM dans notre projet, nous devons ajouter le Community.Toolkit.Mvvm Package NuGet à notre projet. Aucune autre référence ne doit être ajoutée au projet.

Simplifier les propriétés à l’aide de générateurs source

Générateurs source sont une fonctionnalité introduite dans .NET 5 qui permet aux développeurs de générer du code supplémentaire pendant la compilation de projet. Cela signifie que les fichiers de code C # peuvent être produits et incorporés dans l’assemblage final. Cette fonction permet à MVVM Toolkit de simplifier considérablement les modèles de vue en générant le code répétitif que nous avons vu plus tôt dans un fichier séparé, ne laissant que les définitions de champ dans le ViewModel.

La façon de l’utiliser est en héritant du ViewModel ObservableObject. Puisque la classe finale sera divisée en plus d’un .cs fichier, la classe doit être déclarée comme partialcomme suit:

public partial class CurrencyConverterViewModel : ObservableObject
{
    ...
}

Une fois que le modèle a hérité de ObservableObjectnous devons retirer les propriétés complètes et laisser uniquement le champ avec le ObservableProperty Attribut, qui simplifie considérablement le code comme suit:

public partial class CurrencyConverterViewModel : ObservableObject
{
    [ObservableProperty]
    private decimal amount;

    [ObservableProperty]
    private Currency selectedFromCurrency;

    [ObservableProperty]
    private Currency selectedToCurrency;

    [ObservableProperty]
    private decimal result;
    ...
}

Il convient de mentionner qu’il existe plusieurs façons de définir les propriétés, notamment en utilisant camel inférieur syntaxe, démarrant le nom avec un soulignement (_WOLOWERCAMEL), ou même commencer par un m_ (m_lowerCamel). Toutes ces variations généreront un champ en utilisant la syntaxe uppercamel.

Si vous voulez vérifier ce qui s’est passé dans les coulisses pendant la compilation, allez à Votre projet | Dépendances | netx.0-android (x correspond à la version framework) | Analyseurs | CommunityToolkit.Mvvm.SourceGenerators | CommunityToolkit.Mvvm.SourceGenerator.ObservableProperTyGeneratoroù vous trouverez les classes générées par MVVM Toolkit. À l’intérieur du dernier nœud d’arbre, vous trouverez une classe avec le même nom que votre vue ViewModel, contenant du code similaire à ce qui suit:

partial class CurrencyConverterViewModel
{
    ...
    public decimal Amount
    {
        get => amount;
        set
        {
            if (!global::System.Collections.Generic.EqualityComparer<decimal>.Default.Equals(amount, value))
            {
                OnAmountChanging(value);
                OnAmountChanging(default, value);
                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Amount);
                amount = value;
                OnAmountChanged(value);
                OnAmountChanged(default, value);
                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Amount);
            }
        }
    }

    ...
    
    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.4.0.0")]
    partial void OnAmountChanging(decimal value);
    ...
    partial void OnAmountChanging(decimal oldValue, decimal newValue);
    ...    
    partial void OnAmountChanged(decimal value);
    ...
    partial void OnAmountChanged(decimal oldValue, decimal newValue);
    ...
}

Le code ci-dessus informera l’interface utilisateur des modifications sans nécessiter d’implémentation supplémentaire dans le ViewModel. De plus, vous pouvez voir que les méthodes se terminant par Changing sont générés pour agir lorsque la valeur change, ainsi que des méthodes se terminant par Changed Pour effectuer une action lorsqu’une valeur a terminé la mise à jour. Cela peut être implémenté dans votre ViewModel comme dans l’exemple suivant:

public partial class CurrencyConverterViewModel : ObservableObject
{
    ...
    partial void OnAmountChanged(decimal oldValue, decimal newValue)
    {
        Debug.WriteLine($"Amount changed from {oldValue} to {newValue}");
    }
    ...
}

Voyons maintenant comment simplifier l’utilisation des commandes à l’aide de la boîte à outils MVVM.

Simplification des commandes à l’aide de générateurs source

Tout comme le ObservableProperty L’attribut simplifie la création de propriétés dans les modèles de vue, le RelayCommand L’attribut génère le code nécessaire pour éviter le chauffeur lors de la création de commandes.

Pour l’utiliser, vous devez être sûr que votre classe est une classe partielle. L’étape suivante consiste à supprimer toutes les références à ICommand Dans le modèle de vue, ne laissant que les méthodes utilisées pour exécuter des actions dans votre application, qui seront ornées du RelayCommand attribut. Il convient de noter que cet attribut a des capacités de production très flexibles, ce qui lui permet de convertir des méthodes sans paramètres, avec des paramètres, des méthodes asynchrones et même celles avec CancellationToken comme paramètre.

Une chose à garder à l’esprit est que la boîte à outils MVVM ajoutera le mot Command aux méthodes avec le RelayCommand attribut. Par conséquent, si vous nommez généralement vos commandes de cette façon, je vous recommande de les renommer. Dans notre exemple, la méthode ressemblerait à ceci:

[RelayCommand]
private void Convert()
{
    if (SelectedFromCurrency == null || SelectedToCurrency == null)
        return;
    
    Result = Amount * (SelectedToCurrency.Rate / SelectedFromCurrency.Rate);
}

N’oubliez pas que dans le code XAML, vous devez continuer à référencer le nom de commande complet (y compris le Command suffixe), comme dans l’exemple suivant:

 <telerik:RadButton
     BackgroundColor="#007ACC"
     Command="{Binding ConvertCommand}"
     CornerRadius="8"
     HeightRequest="50"
     Text="Convert"
     TextColor="White" />

Après avoir compilé le projet, nous pouvons vérifier le chemin Votre projet | Dépendances | netx.0-android (x correspond à la version framework) | Analyseurs | CommunityToolkit.Mvvm.SourceGenerators | CommunityToolkit.Mvvm.SourceGenerator.relayCommandGeneratoroù nous trouverons une classe avec le même nom que le modèle de vue et une structure similaire à ce qui suit:

partial class CurrencyConverterViewModel
{
    
    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.4.0.0")]
    private global::CommunityToolkit.Mvvm.Input.RelayCommand? convertCommand;
    
    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.4.0.0")]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    public global::CommunityToolkit.Mvvm.Input.IRelayCommand ConvertCommand => convertCommand ??= new global::CommunityToolkit.Mvvm.Input.RelayCommand(new global::System.Action(Convert));
}

Vous pouvez voir que le générateur source a automatiquement créé le ConvertCommandque nous utilisons à partir du code XAML.

Avec ces modifications, l’application se comporterait de la même manière, avec le grand avantage que nous avons réduit le code à quelques lignes, comme on le voit ci-dessous:

public partial class CurrencyConverterViewModel : ObservableObject
{
    [ObservableProperty]
    private decimal amount;

    [ObservableProperty]
    private Currency selectedFromCurrency;

    [ObservableProperty]
    private Currency selectedToCurrency;

    [ObservableProperty]
    private decimal result;        
    
    public ObservableCollection<Currency> Currencies { get; set; }                

    public CurrencyConverterViewModel()
    {            
        Currencies = new ObservableCollection<Currency>
        {
            new Currency { Code = "USD", Rate = 1.0m },
            new Currency { Code = "EUR", Rate = 0.9m },
            new Currency { Code = "GBP", Rate = 0.8m },
            new Currency { Code = "JPY", Rate = 130.0m }
        };
        
        SelectedFromCurrency = Currencies[0];
        SelectedToCurrency = Currencies[1];
        
    }

    [RelayCommand]
    private void Convert()
    {
        if (SelectedFromCurrency == null || SelectedToCurrency == null)
            return;
        
        Result = Amount * (SelectedToCurrency.Rate / SelectedFromCurrency.Rate);
    }   
}

Sans aucun doute, cela représente une amélioration significative dans le code plus simplifié.

Échange de messages entre objets

Une autre fonctionnalité utile dans .net Maui est l’utilisation du IMessenger Interface, qui définit un contrat pour les types qui peuvent être utilisés pour échanger des messages entre différents objets. Si vous avez déjà travaillé avec des formulaires xamarin, c’est le remplacement pour MessagingCentermais s’est amélioré pour éviter les problèmes MessagingCenter avait.

La boîte à outils MVVM propose deux implémentations par défaut de IMessenger: WeakReferenceMessenger et StrongReferenceMessengerchacun avec des caractéristiques uniques. Dans le cas d WeakReferenceMessengercertains de ses avantages incluent:

  • Utilise des références faibles, ce qui signifie qu’il évite automatiquement les fuites de mémoire
  • Il est découplé
  • Plus efficace dans les performances et l’évolutivité
  • Entièrement intégré à la boîte à outils MVVM

D’autre part, StrongReferenceMessenger Utilise de fortes références, ce qui signifie qu’il est de la responsabilité de l’implémentateur de désabonner manuellement les destinataires une fois qu’ils ne sont plus nécessaires. Cependant, il offre de meilleures performances et une utilisation inférieure de la mémoire en retour.

Créons un exemple en utilisant WeakReferenceMessenger. Supposons, pour une raison quelconque, nous devons communiquer du modèle de vue au code de code du fichier d’interface utilisateur à passer, par exemple, le résultat de la conversion. La première étape consiste à définir un message qui spécifie le type de données dont nous devons passer. Dans notre cas, le message sera le suivant:

public class ConversionCompletedMessage : ValueChangedMessage<decimal>
{
    public ConversionCompletedMessage(decimal value) : base(value)
    {
    }
}

Dans le code ci-dessus, vous pouvez voir que nous héritons du ValueChangedMessage classe, qui est conçue pour transporter une valeur associée à un message. En faisant cela, nous héritons d’un Value propriété qui stocke les données que nous souhaitons envoyer.

Ensuite, modifions le modèle de vue afin qu’il soit responsable de l’envoi d’une mise à jour avec le résultat de la conversion:

public partial class CurrencyConverterViewModel : ObservableObject
{
    ...
    [RelayCommand]
    private void Convert()
    {
        if (SelectedFromCurrency == null || SelectedToCurrency == null)
            return;
        
        Result = Amount * (SelectedToCurrency.Rate / SelectedFromCurrency.Rate);

        WeakReferenceMessenger.Default.Send(new ConversionCompletedMessage(Result));
    }
    ...
}

La dernière étape consiste à enregistrer le destinataire du message. Dans notre exemple, nous irons au MainPage.xaml.cs fichier, où nous afficherons la valeur à l’aide d’un DisplayAlert comme suit:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    protected override void OnAppearing()
    {
        WeakReferenceMessenger.Default.Register<ConversionCompletedMessage>(this, (recipient, message) =>
        {
            DisplayAlert("Conversion Completed", $"The conversion result is: {message.Value:N2}", "OK");

        });
    }
}

Conclusion

Tout au long de cet article, vous avez appris certaines fonctionnalités de la boîte à outils MVVM que vous pouvez utiliser dans vos projets .net Maui pour rationaliser le développement.

Tout d’abord, vous avez vu comment simplifier vos modèles de vue ObservableObject classe et le ObservableProperty et RelayCommand attributs. Vous avez également appris à créer des canaux de communication en utilisant des implémentations IMessenger interface.

Sans aucun doute, ce framework puissant a beaucoup plus de joyaux cachés – il est temps de l’utiliser dans vos projets pour simplifier vos anciens de vue.


Prêt à essayer Telerik UI pour .net Maui? Ces composants sont livrés avec un essai gratuit de 30 jours.

Essayer maintenant




Source link
Quitter la version mobile