Uaktualnianie aplikacji przy użyciu pojęć dotyczących maszyn wirtualnych MVVM
Ta seria samouczków została zaprojektowana tak, aby kontynuować samouczek Tworzenie aplikacji MAUI platformy .NET, który utworzył aplikację do tworzenia notatek. W tej części serii dowiesz się, jak wykonywać następujące działania:
- Zaimplementuj wzorzec model-view-viewmodel (MVVM).
- Użyj dodatkowego stylu ciągu zapytania do przekazywania danych podczas nawigacji.
Zdecydowanie zalecamy, aby najpierw wykonać samouczek Tworzenie aplikacji MAUI platformy .NET, ponieważ kod utworzony w tym samouczku jest podstawą tego samouczka. Jeśli kod został utracony lub chcesz rozpocząć od nowa, pobierz ten projekt.
Omówienie maszyny WIRTUALNEJ MVVM
Środowisko deweloperskie .NET MAUI zwykle obejmuje utworzenie interfejsu użytkownika w języku XAML, a następnie dodanie kodu, który działa w interfejsie użytkownika. Złożone problemy z konserwacją mogą wystąpić w miarę modyfikowania aplikacji i zwiększania ich rozmiaru i zakresu. Te problemy obejmują ścisłe sprzężenie między kontrolkami interfejsu użytkownika a logiką biznesową, co zwiększa koszt wprowadzania modyfikacji interfejsu użytkownika oraz trudności z testowaniem jednostkowym takiego kodu.
Wzorzec model-view-viewmodel (MVVM) pomaga w przejrzysty sposób oddzielić logikę biznesową i prezentacji aplikacji od interfejsu użytkownika. Utrzymywanie czystej separacji między logiką aplikacji a interfejsem użytkownika pomaga rozwiązać wiele problemów programistycznych i ułatwia testowanie, konserwację i rozwijanie aplikacji. Może również znacznie poprawić możliwości ponownego użycia kodu i umożliwić deweloperom i projektantom interfejsu użytkownika współpracę w przypadku tworzenia odpowiednich części aplikacji.
Wzorzec
Wzorzec MVVM zawiera trzy podstawowe składniki: model, widok i model widoku. Każdy z nich służy odrębnemu celowi. Na poniższym diagramie przedstawiono relacje między trzema składnikami.
Oprócz zrozumienia obowiązków poszczególnych składników ważne jest również zrozumienie sposobu ich interakcji. Na wysokim poziomie widok "wie o" modelu widoku, a model widoku "wie o" modelu, ale model nie jest świadomy modelu widoku, a model widoku nie jest świadomy widoku. W związku z tym model widoku izoluje widok od modelu i umożliwia ewolucję modelu niezależnie od widoku.
Kluczem do efektywnego korzystania z maszyny MVVM jest zrozumienie, jak uwzględniać kod aplikacji w odpowiednich klasach i jak wchodzić w interakcje z klasami.
Widok
Widok jest odpowiedzialny za definiowanie struktury, układu i wyglądu zawartości wyświetlanej przez użytkownika na ekranie. W idealnym przypadku każdy widok jest definiowany w języku XAML z ograniczonym kodem, który nie zawiera logiki biznesowej. Jednak w niektórych przypadkach kod-behind może zawierać logikę interfejsu użytkownika, która implementuje zachowanie wizualne, które jest trudne do wyrażenia w języku XAML, takich jak animacje.
ViewModel
Model widoku implementuje właściwości i polecenia, z którymi widok może powiązać dane, i powiadamia widok wszelkich zmian stanu za pomocą zdarzeń powiadamiania o zmianie. Właściwości i polecenia udostępniane przez model widoku definiują funkcje, które mają być oferowane przez interfejs użytkownika, ale widok określa sposób wyświetlania tej funkcji.
Model widoku jest również odpowiedzialny za koordynowanie interakcji widoku z dowolnymi wymaganymi klasami modeli. Zazwyczaj istnieje relacja jeden do wielu między modelem widoku a klasami modeli.
Każdy model widoku udostępnia dane z modelu w postaci, którą widok może łatwo wykorzystywać. W tym celu model widoku czasami wykonuje konwersję danych. Umieszczenie tej konwersji danych w modelu widoku jest dobrym pomysłem, ponieważ udostępnia właściwości, z którymi widok może być powiązany. Na przykład model widoku może łączyć wartości dwóch właściwości, aby ułatwić wyświetlanie go przez widok.
Ważne
.NET MAUI marshals powiązania aktualizacji wątku interfejsu użytkownika. W przypadku korzystania z maszyny MVVM umożliwia to aktualizowanie właściwości modelu widoku powiązanego z danymi z dowolnego wątku, a aparat powiązań programu .NET MAUI wprowadza aktualizacje do wątku interfejsu użytkownika.
Model
Klasy modeli to klasy inne niż wizualne, które hermetyzują dane aplikacji. W związku z tym model może być uważany za reprezentujący model domeny aplikacji, który zwykle zawiera model danych wraz z logiką biznesową i walidacją.
Aktualizowanie modelu
W pierwszej części samouczka zaimplementujesz wzorzec model-view-viewmodel (MVVM). Aby rozpocząć, otwórz rozwiązanie Notes.sln w programie Visual Studio.
Czyszczenie modelu
W poprzednim samouczku typy modeli działały zarówno jako model (dane), jak i jako model widoku (przygotowywanie danych), który został zamapowany bezpośrednio do widoku. W poniższej tabeli opisano model:
Plik kodu | opis |
---|---|
Modele/About.cs | About Model. Zawiera pola tylko do odczytu, które opisują samą aplikację, takie jak tytuł i wersja aplikacji. |
Modele/Note.cs | Note Model. Reprezentuje notatkę. |
Modele/AllNotes.cs | AllNotes Model. Ładuje wszystkie notatki na urządzeniu do kolekcji. |
Myśląc o samej aplikacji, istnieje tylko jeden element danych używany przez aplikację , Note
czyli . Notatki są ładowane z urządzenia, zapisywane na urządzeniu i edytowane za pośrednictwem interfejsu użytkownika aplikacji. Naprawdę nie ma potrzeby i About
AllNotes
modeli. Usuń te modele z projektu:
- Znajdź okienko Eksplorator rozwiązań programu Visual Studio.
- Kliknij prawym przyciskiem myszy plik Models\About.cs i wybierz polecenie Usuń. Naciśnij przycisk OK , aby usunąć plik.
- Kliknij prawym przyciskiem myszy plik Models\AllNotes.cs i wybierz polecenie Usuń. Naciśnij przycisk OK , aby usunąć plik.
Jedynym pozostałym plikiem modelu jest plik Models\Note.cs .
Aktualizowanie modelu
Model Note
zawiera:
- Unikatowy identyfikator, który jest nazwą pliku notatki przechowywanej na urządzeniu.
- Tekst notatki.
- Data wskazująca, kiedy notatka została utworzona lub ostatnia aktualizacja.
Obecnie ładowanie i zapisywanie modelu zostało wykonane za pośrednictwem widoków, a w niektórych przypadkach przez inne typy modeli, które właśnie usunięto. Kod podany dla Note
tego typu powinien być następujący:
namespace Notes.Models;
internal class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
Note
Model zostanie rozszerzony w celu obsługi ładowania, zapisywania i usuwania notatek.
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Models\Note.cs.
W edytorze kodu dodaj do klasy następujące dwie metody
Note
. Te metody są oparte na wystąpieniach i obsługują zapisywanie lub usuwanie bieżącej notatki do lub z urządzenia, odpowiednio:public void Save() => File.WriteAllText(System.IO.Path.Combine(FileSystem.AppDataDirectory, Filename), Text); public void Delete() => File.Delete(System.IO.Path.Combine(FileSystem.AppDataDirectory, Filename));
Aplikacja musi załadować notatki na dwa sposoby, ładują pojedynczą notatkę z pliku i ładują wszystkie notatki na urządzeniu. Kod do obsługi ładowania może być
static
elementami członkowskimi, a nie wymaga uruchomienia wystąpienia klasy.Dodaj następujący kod do klasy, aby załadować notatkę według nazwy pliku:
public static Note Load(string filename) { filename = System.IO.Path.Combine(FileSystem.AppDataDirectory, filename); if (!File.Exists(filename)) throw new FileNotFoundException("Unable to find file on local storage.", filename); return new() { Filename = Path.GetFileName(filename), Text = File.ReadAllText(filename), Date = File.GetLastWriteTime(filename) }; }
Ten kod przyjmuje nazwę pliku jako parametr, tworzy ścieżkę do miejsca przechowywania notatek na urządzeniu i próbuje załadować plik, jeśli istnieje.
Drugim sposobem ładowania notatek jest wyliczenie wszystkich notatek na urządzeniu i załadowanie ich do kolekcji.
Dodaj następujący kod do klasy:
public static IEnumerable<Note> LoadAll() { // Get the folder where the notes are stored. string appDataPath = FileSystem.AppDataDirectory; // Use Linq extensions to load the *.notes.txt files. return Directory // Select the file names from the directory .EnumerateFiles(appDataPath, "*.notes.txt") // Each file name is used to load a note .Select(filename => Note.Load(Path.GetFileName(filename))) // With the final collection of notes, order them by date .OrderByDescending(note => note.Date); }
Ten kod zwraca wyliczalną kolekcję
Note
typów modeli, pobierając pliki na urządzeniu, które są zgodne ze wzorcem pliku notatek: *.notes.txt. Każda nazwa pliku jest przekazywana doLoad
metody, ładuje pojedynczą notatkę. Na koniec kolekcja notatek jest uporządkowana według daty każdej notatki i zwracana do obiektu wywołującego.Na koniec dodaj konstruktora do klasy, który ustawia wartości domyślne właściwości, w tym losową nazwę pliku:
public Note() { Filename = $"{Path.GetRandomFileName()}.notes.txt"; Date = DateTime.Now; Text = ""; }
Kod Note
klasy powinien wyglądać następująco:
namespace Notes.Models;
internal class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
public Note()
{
Filename = $"{Path.GetRandomFileName()}.notes.txt";
Date = DateTime.Now;
Text = "";
}
public void Save() =>
File.WriteAllText(System.IO.Path.Combine(FileSystem.AppDataDirectory, Filename), Text);
public void Delete() =>
File.Delete(System.IO.Path.Combine(FileSystem.AppDataDirectory, Filename));
public static Note Load(string filename)
{
filename = System.IO.Path.Combine(FileSystem.AppDataDirectory, filename);
if (!File.Exists(filename))
throw new FileNotFoundException("Unable to find file on local storage.", filename);
return
new()
{
Filename = Path.GetFileName(filename),
Text = File.ReadAllText(filename),
Date = File.GetLastWriteTime(filename)
};
}
public static IEnumerable<Note> LoadAll()
{
// Get the folder where the notes are stored.
string appDataPath = FileSystem.AppDataDirectory;
// Use Linq extensions to load the *.notes.txt files.
return Directory
// Select the file names from the directory
.EnumerateFiles(appDataPath, "*.notes.txt")
// Each file name is used to load a note
.Select(filename => Note.Load(Path.GetFileName(filename)))
// With the final collection of notes, order them by date
.OrderByDescending(note => note.Date);
}
}
Teraz, gdy Note
model został ukończony, można utworzyć modele widoku.
Tworzenie modelu viewmodel — informacje
Przed dodaniem modeli widoku do projektu dodaj odwołanie do zestawu narzędzi MVVM Community Toolkit. Ta biblioteka jest dostępna w systemie NuGet i udostępnia typy i systemy, które ułatwiają implementowanie wzorca MVVM.
W okienku Eksplorator rozwiązań programu Visual Studio kliknij prawym przyciskiem myszy projekt Notatki Zarządzanie pakietami >NuGet.
Wybierz kartę Przeglądaj.
Wyszukaj ciąg communitytoolkit mvvm i wybierz
CommunityToolkit.Mvvm
pakiet, który powinien być pierwszym wynikiem.Upewnij się, że wybrano co najmniej wersję 8. Ten samouczek został napisany przy użyciu wersji 8.0.0.
Następnie wybierz pozycję Zainstaluj i zaakceptuj wszystkie wyświetlane monity.
Teraz możesz rozpocząć aktualizowanie projektu, dodając modele widoku.
Rozdzielanie z modelami widoków
Relacja widoku do widoku modelu opiera się w dużym stopniu na systemie powiązań udostępnianym przez interfejs użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI). Aplikacja używa już powiązania w widokach, aby wyświetlić listę notatek i przedstawić tekst i datę pojedynczej notatki. Logika aplikacji jest obecnie dostarczana przez kod widoku i jest bezpośrednio powiązana z widokiem. Na przykład gdy użytkownik edytuje notatkę i naciśnie przycisk Zapisz , Clicked
zostanie zgłoszone zdarzenie przycisku . Następnie kod programu obsługi zdarzeń zapisuje tekst notatki w pliku i przechodzi do poprzedniego ekranu.
Logika aplikacji w kodzie widoku może stać się problemem podczas zmiany widoku. Jeśli na przykład przycisk zostanie zastąpiony inną kontrolką wprowadzania lub nazwa kontrolki zostanie zmieniona, programy obsługi zdarzeń mogą stać się nieprawidłowe. Niezależnie od sposobu projektowania widoku celem widoku jest wywołanie jakiejś logiki aplikacji i przedstawienie informacji użytkownikowi. W przypadku tej aplikacji przycisk zapisuje notatkę, Save
a następnie wraca do poprzedniego ekranu.
Model widoku udostępnia aplikacji określone miejsce do umieszczenia logiki aplikacji niezależnie od sposobu projektowania interfejsu użytkownika lub sposobu ładowania lub zapisywania danych. Model widoku to klej reprezentujący model danych i współdziałający z nim w imieniu widoku.
Modele widoku są przechowywane w folderze ViewModels .
- Znajdź okienko Eksplorator rozwiązań programu Visual Studio.
- Kliknij prawym przyciskiem myszy projekt Notatki i wybierz polecenie Dodaj>nowy folder. Nadaj folderowi nazwę ViewModels.
- Kliknij prawym przyciskiem myszy folder> ViewModels Dodaj>klasę i nadaj mu nazwę AboutViewModel.cs.
- Powtórz poprzedni krok i utwórz jeszcze dwa modele widoku:
- NoteViewModel.cs
- NotesViewModel.cs
Struktura projektu powinna wyglądać podobnie do poniższej ilustracji:
Informacje o modelu viewmodel i widoku Informacje
Widok Informacje wyświetla niektóre dane na ekranie i opcjonalnie przechodzi do witryny internetowej, aby uzyskać więcej informacji. Ponieważ ten widok nie ma żadnych danych do zmiany, na przykład za pomocą kontrolki wprowadzania tekstu lub wybierania elementów z listy, dobrym kandydatem jest zademonstrowanie dodania modelu widoku. W przypadku modelu widoku Informacje nie ma modelu tworzenia kopii zapasowych.
Utwórz model viewmodel — informacje:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję ViewModels\AboutViewModel.cs.
Wklej następujący kod:
using CommunityToolkit.Mvvm.Input; using System.Windows.Input; namespace Notes.ViewModels; internal class AboutViewModel { public string Title => AppInfo.Name; public string Version => AppInfo.VersionString; public string MoreInfoUrl => "https://aka.ms/maui"; public string Message => "This app is written in XAML and C# with .NET MAUI."; public ICommand ShowMoreInfoCommand { get; } public AboutViewModel() { ShowMoreInfoCommand = new AsyncRelayCommand(ShowMoreInfo); } async Task ShowMoreInfo() => await Launcher.Default.OpenAsync(MoreInfoUrl); }
Poprzedni fragment kodu zawiera pewne właściwości reprezentujące informacje o aplikacji, takie jak nazwa i wersja. Ten fragment kodu jest dokładnie taki sam jak usunięty wcześniej model About (Informacje o usuniętym wcześniej). Jednak ten model widoku zawiera nową koncepcję, ShowMoreInfoCommand
właściwość polecenia.
Polecenia to powiązane akcje, które wywołują kod, i są doskonałym miejscem do umieszczenia logiki aplikacji. W tym przykładzie ShowMoreInfoCommand
wskazuje metodę ShowMoreInfo
, która otwiera przeglądarkę internetową na określoną stronę. Więcej informacji na temat systemu poleceń znajdziesz w następnej sekcji.
Widok — informacje
Widok Informacje należy nieco zmienić, aby podłączyć go do modelu widoków utworzonego w poprzedniej sekcji. W pliku Views\AboutPage.xaml zastosuj następujące zmiany:
xmlns:models
Zaktualizuj przestrzeń nazw XML naxmlns:viewModels
przestrzeń nazw platformy .NET i na docelową przestrzeń nazw platformyNotes.ViewModels
.NET.- Zmień właściwość na
ContentPage.BindingContext
nowe wystąpienieAbout
modelu viewmodel. - Usuń procedurę obsługi zdarzeń przycisku
Clicked
i użyjCommand
właściwości .
Zaktualizuj widok Informacje:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Views\AboutPage.xaml.
Wklej następujący kod:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewModels="clr-namespace:Notes.ViewModels" x:Class="Notes.Views.AboutPage"> <ContentPage.BindingContext> <viewModels:AboutViewModel /> </ContentPage.BindingContext> <VerticalStackLayout Spacing="10" Margin="10"> <HorizontalStackLayout Spacing="10"> <Image Source="dotnet_bot.png" SemanticProperties.Description="The dot net bot waving hello!" HeightRequest="64" /> <Label FontSize="22" FontAttributes="Bold" Text="{Binding Title}" VerticalOptions="End" /> <Label FontSize="22" Text="{Binding Version}" VerticalOptions="End" /> </HorizontalStackLayout> <Label Text="{Binding Message}" /> <Button Text="Learn more..." Command="{Binding ShowMoreInfoCommand}" /> </VerticalStackLayout> </ContentPage>
Poprzedni fragment kodu wyróżnia wiersze, które zostały zmienione w tej wersji widoku.
Zwróć uwagę, że przycisk używa Command
właściwości . Wiele kontrolek ma właściwość wywoływaną Command
, gdy użytkownik wchodzi w interakcję z kontrolką. W przypadku użycia z przyciskiem polecenie jest wywoływane, gdy użytkownik naciska przycisk, podobnie jak Clicked
wywoływana procedura obsługi zdarzeń, z tą różnicą, że można powiązać Command
z właściwością w modelu viewmodel.
W tym widoku, gdy użytkownik naciska przycisk, jest wywoływany Command
. Właściwość Command
jest powiązana z właściwością ShowMoreInfoCommand
w modelu viewmodel, a po wywołaniu uruchamia kod w ShowMoreInfo
metodzie , która otwiera przeglądarkę internetową na określonej stronie.
Czyszczenie kodu —informacje
Przycisk ShowMoreInfo
nie korzysta z procedury obsługi zdarzeń, dlatego LearnMore_Clicked
kod powinien zostać usunięty z pliku Views\AboutPage.xaml.cs . Usuń ten kod, klasa powinna zawierać tylko konstruktor:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Widoki\AboutPage.xaml.cs.
Napiwek
Aby wyświetlić plik, może być konieczne rozwinięcie pozycji Views\AboutPage.xaml .
Zastąp kod następującym fragmentem kodu:
namespace Notes.Views; public partial class AboutPage : ContentPage { public AboutPage() { InitializeComponent(); } }
Tworzenie modelu viewmodel notatek
Celem aktualizacji widoku Notatki jest przeniesienie jak największej liczby funkcji z kodu XAML i umieszczenie go w modelu viewmodel notatki.
Model widoku notatek
W zależności od tego, czego wymaga widok Notatki, model widoków notatki musi podać następujące elementy:
- Tekst notatki.
- Data/godzina utworzenia lub ostatniej aktualizacji notatki.
- Polecenie, które zapisuje notatkę.
- Polecenie, które usuwa notatkę.
Utwórz model widoku Notatki:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję ViewModels\NoteViewModel.cs.
Zastąp kod w tym pliku następującym fragmentem kodu:
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.ComponentModel; using System.Windows.Input; namespace Notes.ViewModels; internal class NoteViewModel : ObservableObject, IQueryAttributable { private Models.Note _note; }
Ten kod jest pustym
Note
modelem widoku, w którym dodasz właściwości i polecenia do obsługiNote
widoku. Zwróć uwagę, żeCommunityToolkit.Mvvm.ComponentModel
przestrzeń nazw jest importowana. Ta przestrzeń nazw udostępnia elementObservableObject
używany jako klasa bazowa. Więcej informacjiObservableObject
znajdziesz w następnym kroku.CommunityToolkit.Mvvm.Input
Przestrzeń nazw jest również importowana. Ta przestrzeń nazw udostępnia niektóre typy poleceń, które wywołują metody asynchronicznie.Model
Models.Note
jest przechowywany jako pole prywatne. Właściwości i metody tej klasy będą używać tego pola.Dodaj następujące właściwości do klasy:
public string Text { get => _note.Text; set { if (_note.Text != value) { _note.Text = value; OnPropertyChanged(); } } } public DateTime Date => _note.Date; public string Identifier => _note.Filename;
Właściwości
Date
iIdentifier
to proste właściwości, które po prostu pobierają odpowiednie wartości z modelu.Napiwek
W przypadku właściwości składnia
=>
tworzy właściwość get-only, w której instrukcja z prawej strony=>
musi zostać obliczona na wartość, która ma zostać zwrócona.Właściwość
Text
najpierw sprawdza, czy ustawiona wartość jest inną wartością. Jeśli wartość jest inna, ta wartość jest przekazywana do właściwości modelu, a metoda jest wywoływanaOnPropertyChanged
.Metoda
OnPropertyChanged
jest dostarczana przez klasę bazowąObservableObject
. Ta metoda używa nazwy kodu wywołującego, w tym przypadku nazwy właściwości Text i zgłaszaObservableObject.PropertyChanged
zdarzenie. To zdarzenie dostarcza nazwę właściwości do wszystkich subskrybentów zdarzeń. System powiązań dostarczony przez program .NET MAUI rozpoznaje to zdarzenie i aktualizuje wszelkie powiązane powiązania w interfejsie użytkownika. W przypadku modelu viewmodel notatki, gdyText
właściwość się zmienia, zdarzenie jest wywoływane, a dowolny element interfejsu użytkownika powiązany zText
właściwością jest powiadamiany o zmianie właściwości.Dodaj następujące właściwości polecenia do klasy, które są poleceniami, z którymi widok może powiązać:
public ICommand SaveCommand { get; private set; } public ICommand DeleteCommand { get; private set; }
Dodaj następujące konstruktory do klasy:
public NoteViewModel() { _note = new Models.Note(); SaveCommand = new AsyncRelayCommand(Save); DeleteCommand = new AsyncRelayCommand(Delete); } public NoteViewModel(Models.Note note) { _note = note; SaveCommand = new AsyncRelayCommand(Save); DeleteCommand = new AsyncRelayCommand(Delete); }
Te dwa konstruktory są używane do utworzenia modelu viewmodel z nowym modelem tworzenia kopii zapasowych, który jest pustą notatką, lub do utworzenia modelu viewmodel używającego określonego wystąpienia modelu.
Konstruktory konfigurują również polecenia dla modelu viewmodel. Następnie dodaj kod dla tych poleceń.
Save
Dodaj metody iDelete
:private async Task Save() { _note.Date = DateTime.Now; _note.Save(); await Shell.Current.GoToAsync($"..?saved={_note.Filename}"); } private async Task Delete() { _note.Delete(); await Shell.Current.GoToAsync($"..?deleted={_note.Filename}"); }
Te metody są wywoływane przez skojarzone polecenia. Wykonują powiązane akcje w modelu i sprawiają, że aplikacja przechodzi do poprzedniej strony. Parametr ciągu zapytania jest dodawany do
..
ścieżki nawigacji wskazującej, która akcja została podjęta i unikatowy identyfikator notatki.Następnie dodaj metodę
ApplyQueryAttributes
do klasy, która spełnia wymagania interfejsu IQueryAttributable :void IQueryAttributable.ApplyQueryAttributes(IDictionary<string, object> query) { if (query.ContainsKey("load")) { _note = Models.Note.Load(query["load"].ToString()); RefreshProperties(); } }
Gdy strona lub kontekst powiązania strony implementuje ten interfejs, parametry ciągu zapytania używane w nawigacji są przekazywane do
ApplyQueryAttributes
metody . Ten model widoku jest używany jako kontekst powiązania dla widoku Notatki. Po przejściu do widoku Notatki kontekst powiązania widoku (ten model widoku) jest przekazywany parametry ciągu zapytania używane podczas nawigacji.Ten kod sprawdza, czy
load
klucz został podany w słownikuquery
. Jeśli ten klucz zostanie znaleziony, wartość powinna być identyfikatorem (nazwą pliku) notatki do załadowania. Ta uwaga jest ładowana i ustawiana jako obiekt modelu bazowego tego wystąpienia modelu viewmodel.Na koniec dodaj te dwie metody pomocnicze do klasy:
public void Reload() { _note = Models.Note.Load(_note.Filename); RefreshProperties(); } private void RefreshProperties() { OnPropertyChanged(nameof(Text)); OnPropertyChanged(nameof(Date)); }
Metoda
Reload
jest metodą pomocnika, która odświeża obiekt modelu pomocniczego, ponownie ładując go z magazynu urządzeńMetoda
RefreshProperties
jest inną metodą pomocnika, aby upewnić się, że wszyscy subskrybenci związani z tym obiektem zostaną powiadomieni, żeText
właściwości iDate
uległy zmianie. Ponieważ model bazowy (_note
pole) jest zmieniany, gdy notatka jest ładowana podczas nawigacji,Text
właściwości iDate
nie są w rzeczywistości ustawione na nowe wartości. Ponieważ te właściwości nie są ustawiane bezpośrednio, żadne powiązania dołączone do tych właściwości nie zostaną powiadomione, ponieważOnPropertyChanged
nie są wywoływane dla każdej właściwości.RefreshProperties
zapewnia odświeżanie powiązań z tymi właściwościami.
Kod klasy powinien wyglądać podobnie do następującego fragmentu kodu:
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using System.Windows.Input;
namespace Notes.ViewModels;
internal class NoteViewModel : ObservableObject, IQueryAttributable
{
private Models.Note _note;
public string Text
{
get => _note.Text;
set
{
if (_note.Text != value)
{
_note.Text = value;
OnPropertyChanged();
}
}
}
public DateTime Date => _note.Date;
public string Identifier => _note.Filename;
public ICommand SaveCommand { get; private set; }
public ICommand DeleteCommand { get; private set; }
public NoteViewModel()
{
_note = new Models.Note();
SaveCommand = new AsyncRelayCommand(Save);
DeleteCommand = new AsyncRelayCommand(Delete);
}
public NoteViewModel(Models.Note note)
{
_note = note;
SaveCommand = new AsyncRelayCommand(Save);
DeleteCommand = new AsyncRelayCommand(Delete);
}
private async Task Save()
{
_note.Date = DateTime.Now;
_note.Save();
await Shell.Current.GoToAsync($"..?saved={_note.Filename}");
}
private async Task Delete()
{
_note.Delete();
await Shell.Current.GoToAsync($"..?deleted={_note.Filename}");
}
void IQueryAttributable.ApplyQueryAttributes(IDictionary<string, object> query)
{
if (query.ContainsKey("load"))
{
_note = Models.Note.Load(query["load"].ToString());
RefreshProperties();
}
}
public void Reload()
{
_note = Models.Note.Load(_note.Filename);
RefreshProperties();
}
private void RefreshProperties()
{
OnPropertyChanged(nameof(Text));
OnPropertyChanged(nameof(Date));
}
}
Widok notatek
Po utworzeniu modelu viewmodel zaktualizuj widok Notatki. W pliku Views\NotePage.xaml zastosuj następujące zmiany:
xmlns:viewModels
Dodaj przestrzeń nazw XML, która jest przeznaczona dla przestrzeni nazw platformyNotes.ViewModels
.NET.- Dodaj element
BindingContext
do strony. - Usuń i zapisz programy obsługi zdarzeń przycisku
Clicked
i zastąp je poleceniami.
Zaktualizuj widok Notatki:
- W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Views\NotePage.xaml, aby otworzyć edytor XAML.
- Wklej następujący kod:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:Notes.ViewModels"
x:Class="Notes.Views.NotePage"
Title="Note">
<ContentPage.BindingContext>
<viewModels:NoteViewModel />
</ContentPage.BindingContext>
<VerticalStackLayout Spacing="10" Margin="5">
<Editor x:Name="TextEditor"
Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid ColumnDefinitions="*,*" ColumnSpacing="4">
<Button Text="Save"
Command="{Binding SaveCommand}"/>
<Button Grid.Column="1"
Text="Delete"
Command="{Binding DeleteCommand}"/>
</Grid>
</VerticalStackLayout>
</ContentPage>
Wcześniej ten widok nie zadeklarował kontekstu powiązania, ponieważ został dostarczony przez kod samej strony. Ustawienie kontekstu powiązania bezpośrednio w języku XAML zapewnia dwie elementy:
W czasie wykonywania po przejściu do strony zostanie wyświetlona pusta notatka. Dzieje się tak, ponieważ wywoływany jest konstruktor bez parametrów dla kontekstu powiązania, modelu viewmodel. Jeśli pamiętasz poprawnie, konstruktor bez parametrów dla modelu ViewModel notatki tworzy pustą notatkę.
Funkcja IntelliSense w edytorze XAML wyświetla dostępne właściwości natychmiast po rozpoczęciu wpisywania
{Binding
składni. Składnia jest również weryfikowana i ostrzega o nieprawidłowej wartości. Spróbuj zmienić składnię powiązania dla elementuSaveCommand
Save123Command
na . Po umieszczeniu kursora myszy na tekście zauważysz, że zostanie wyświetlona etykietka narzędzia informująca o tym, że polecenie Save123Command nie zostanie znalezione. To powiadomienie nie jest uznawane za błąd, ponieważ powiązania są dynamiczne, jest to naprawdę małe ostrzeżenie, które może pomóc zauważyć podczas wpisywania nieprawidłowej właściwości.Jeśli zmieniono polecenie SaveCommand na inną wartość, przywróć ją teraz.
Czyszczenie kodu notatki
Teraz, gdy interakcja z widokiem została zmieniona z programów obsługi zdarzeń na polecenia, otwórz plik Views\NotePage.xaml.cs i zastąp cały kod klasą zawierającą tylko konstruktor:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Widoki\NotePage.xaml.cs.
Napiwek
Aby wyświetlić plik, może być konieczne rozwinięcie pozycji Views\NotePage.xaml .
Zastąp kod następującym fragmentem kodu:
namespace Notes.Views; public partial class NotePage : ContentPage { public NotePage() { InitializeComponent(); } }
Tworzenie modelu widoków notatek
Ostateczna para viewmodel-view to widok Widok notatki i Wszystkienotes. Obecnie widok jest jednak wiązany bezpośrednio z modelem, który został usunięty na początku tego samouczka. Celem aktualizowania widoku AllNotes jest przeniesienie jak największej ilości funkcji poza kod XAML i umieszczenie go w modelu widoków. Ponownie korzyścią jest to, że widok może zmienić jego projekt z niewielkim wpływem na kod.
Model widoku notatek
W zależności od tego, co ma być wyświetlany widok AllNotes i jakie interakcje użytkownik wykona, model widoków notatek musi podać następujące elementy:
- Kolekcja notatek.
- Polecenie do obsługi przechodzenia do notatki.
- Polecenie utworzenia nowej notatki.
- Zaktualizuj listę notatek po utworzeniu, usunięciu lub zmianie.
Utwórz model widoków notatek:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję ViewModels\NotesViewModel.cs.
Zastąp kod w tym pliku następującym kodem:
using CommunityToolkit.Mvvm.Input; using System.Collections.ObjectModel; using System.Windows.Input; namespace Notes.ViewModels; internal class NotesViewModel: IQueryAttributable { }
Ten kod jest pusty
NotesViewModel
, w którym dodasz właściwości i polecenia do obsługiAllNotes
widoku.NotesViewModel
W kodzie klasy dodaj następujące właściwości:public ObservableCollection<ViewModels.NoteViewModel> AllNotes { get; } public ICommand NewCommand { get; } public ICommand SelectNoteCommand { get; }
Właściwość
AllNotes
jest właściwościąObservableCollection
, która przechowuje wszystkie notatki załadowane z urządzenia. Dwa polecenia będą używane przez widok do wyzwalania akcji tworzenia notatki lub wybierania istniejącej notatki.Dodaj konstruktor bez parametrów do klasy, który inicjuje polecenia i ładuje notatki z modelu:
public NotesViewModel() { AllNotes = new ObservableCollection<ViewModels.NoteViewModel>(Models.Note.LoadAll().Select(n => new NoteViewModel(n))); NewCommand = new AsyncRelayCommand(NewNoteAsync); SelectNoteCommand = new AsyncRelayCommand<ViewModels.NoteViewModel>(SelectNoteAsync); }
Zwróć uwagę, że
AllNotes
kolekcja używaModels.Note.LoadAll
metody do wypełniania obserwowalnej kolekcji notatkami. MetodaLoadAll
zwraca notatki jakoModels.Note
typ, ale obserwowalna kolekcja jest kolekcjąViewModels.NoteViewModel
typów. Kod używaSelect
rozszerzenia Linq do tworzenia wystąpień modelu viewmodel z modeli notatek zwróconych z klasyLoadAll
.Utwórz metody, których celem są polecenia:
private async Task NewNoteAsync() { await Shell.Current.GoToAsync(nameof(Views.NotePage)); } private async Task SelectNoteAsync(ViewModels.NoteViewModel note) { if (note != null) await Shell.Current.GoToAsync($"{nameof(Views.NotePage)}?load={note.Identifier}"); }
Zwróć uwagę, że
NewNoteAsync
metoda nie bierze parametruSelectNoteAsync
podczas wykonywania tej metody. Polecenia mogą opcjonalnie mieć jeden parametr, który jest udostępniany podczas wywoływanego polecenia. W przypadkuSelectNoteAsync
metody parametr reprezentuje zaznaczoną notatkę.Na koniec zaimplementuj metodę
IQueryAttributable.ApplyQueryAttributes
:void IQueryAttributable.ApplyQueryAttributes(IDictionary<string, object> query) { if (query.ContainsKey("deleted")) { string noteId = query["deleted"].ToString(); NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault(); // If note exists, delete it if (matchedNote != null) AllNotes.Remove(matchedNote); } else if (query.ContainsKey("saved")) { string noteId = query["saved"].ToString(); NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault(); // If note is found, update it if (matchedNote != null) matchedNote.Reload(); // If note isn't found, it's new; add it. else AllNotes.Add(new NoteViewModel(Note.Load(noteId))); } }
Model viewmodel notatki utworzony w poprzednim kroku samouczka używał nawigacji po zapisaniu lub usunięciu notatki. Model widoku wrócił do widoku AllNotes, z którym jest skojarzony ten model widoku. Ten kod wykrywa, czy ciąg zapytania zawiera
deleted
klucz lubsaved
. Wartość klucza jest unikatowym identyfikatorem notatki.Jeśli notatka została usunięta, ta uwaga jest zgodna z kolekcją
AllNotes
przez podany identyfikator i usunięta.Istnieją dwa możliwe przyczyny zapisania notatki. Notatka została właśnie utworzona lub zmieniono istniejącą notatkę. Jeśli notatka znajduje się już w kolekcji
AllNotes
, jest to notatka, która została zaktualizowana. W takim przypadku należy odświeżyć wystąpienie notatki w kolekcji. Jeśli w kolekcji brakuje notatki, jest to nowa notatka i musi zostać dodana do kolekcji.
Kod klasy powinien wyglądać podobnie do następującego fragmentu kodu:
using CommunityToolkit.Mvvm.Input;
using Notes.Models;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace Notes.ViewModels;
internal class NotesViewModel : IQueryAttributable
{
public ObservableCollection<ViewModels.NoteViewModel> AllNotes { get; }
public ICommand NewCommand { get; }
public ICommand SelectNoteCommand { get; }
public NotesViewModel()
{
AllNotes = new ObservableCollection<ViewModels.NoteViewModel>(Models.Note.LoadAll().Select(n => new NoteViewModel(n)));
NewCommand = new AsyncRelayCommand(NewNoteAsync);
SelectNoteCommand = new AsyncRelayCommand<ViewModels.NoteViewModel>(SelectNoteAsync);
}
private async Task NewNoteAsync()
{
await Shell.Current.GoToAsync(nameof(Views.NotePage));
}
private async Task SelectNoteAsync(ViewModels.NoteViewModel note)
{
if (note != null)
await Shell.Current.GoToAsync($"{nameof(Views.NotePage)}?load={note.Identifier}");
}
void IQueryAttributable.ApplyQueryAttributes(IDictionary<string, object> query)
{
if (query.ContainsKey("deleted"))
{
string noteId = query["deleted"].ToString();
NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault();
// If note exists, delete it
if (matchedNote != null)
AllNotes.Remove(matchedNote);
}
else if (query.ContainsKey("saved"))
{
string noteId = query["saved"].ToString();
NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault();
// If note is found, update it
if (matchedNote != null)
matchedNote.Reload();
// If note isn't found, it's new; add it.
else
AllNotes.Add(new NoteViewModel(Note.Load(noteId)));
}
}
}
Widok AllNotes
Po utworzeniu modelu viewmodel zaktualizuj widok AllNotes, aby wskazywał właściwości modelu viewmodel. W pliku Views\AllNotesPage.xaml zastosuj następujące zmiany:
xmlns:viewModels
Dodaj przestrzeń nazw XML, która jest przeznaczona dla przestrzeni nazw platformyNotes.ViewModels
.NET.- Dodaj element
BindingContext
do strony. - Usuń zdarzenie przycisku
Clicked
paska narzędzi i użyjCommand
właściwości . - Zmień element
CollectionView
, aby powiązać elementItemSource
z elementemAllNotes
. - Zmień wartość
CollectionView
, aby użyć poleceń, aby reagować na zmiany wybranego elementu.
Zaktualizuj widok AllNotes:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Views\AllNotesPage.xaml.
Wklej następujący kod:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewModels="clr-namespace:Notes.ViewModels" x:Class="Notes.Views.AllNotesPage" Title="Your Notes"> <ContentPage.BindingContext> <viewModels:NotesViewModel /> </ContentPage.BindingContext> <!-- Add an item to the toolbar --> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" Command="{Binding NewCommand}" IconImageSource="{FontImage Glyph='+', Color=Black, Size=22}" /> </ContentPage.ToolbarItems> <!-- Display notes in a list --> <CollectionView x:Name="notesCollection" ItemsSource="{Binding AllNotes}" Margin="20" SelectionMode="Single" SelectionChangedCommand="{Binding SelectNoteCommand}" SelectionChangedCommandParameter="{Binding Source={RelativeSource Self}, Path=SelectedItem}"> <!-- Designate how the collection of items are laid out --> <CollectionView.ItemsLayout> <LinearItemsLayout Orientation="Vertical" ItemSpacing="10" /> </CollectionView.ItemsLayout> <!-- Define the appearance of each item in the list --> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout> <Label Text="{Binding Text}" FontSize="22"/> <Label Text="{Binding Date}" FontSize="14" TextColor="Silver"/> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
Pasek narzędzi nie używa Clicked
już zdarzenia i zamiast tego używa polecenia .
Program CollectionView
obsługuje polecenie za pomocą SelectionChangedCommand
właściwości i SelectionChangedCommandParameter
. W zaktualizowanym kodzie XAML właściwość jest powiązana z modelem SelectNoteCommand
viewmodel, co oznacza, SelectionChangedCommand
że polecenie jest wywoływane po zmianie wybranego elementu. Po wywołaniu SelectionChangedCommandParameter
polecenia wartość właściwości jest przekazywana do polecenia .
Przyjrzyj się powiązaniu używanego dla elementu CollectionView
:
<CollectionView x:Name="notesCollection"
ItemsSource="{Binding AllNotes}"
Margin="20"
SelectionMode="Single"
SelectionChangedCommand="{Binding SelectNoteCommand}"
SelectionChangedCommandParameter="{Binding Source={RelativeSource Self}, Path=SelectedItem}">
Właściwość SelectionChangedCommandParameter
używa Source={RelativeSource Self}
powiązania. Odwołuje Self
się do bieżącego obiektu , czyli CollectionView
. Zwróć uwagę, że ścieżka powiązania jest właściwością SelectedItem
. Gdy polecenie jest wywoływane przez zmianę wybranego elementu, polecenie jest wywoływane, SelectNoteCommand
a wybrany element jest przekazywany do polecenia jako parametr.
Czyszczenie kodu AllNotes
Teraz, gdy interakcja z widokiem została zmieniona z programów obsługi zdarzeń na polecenia, otwórz plik Views\AllNotesPage.xaml.cs i zastąp cały kod klasą zawierającą tylko konstruktor:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Widoki\AllNotesPage.xaml.cs.
Napiwek
Aby wyświetlić plik, może być konieczne rozwinięcie pozycji Views\AllNotesPage.xaml .
Zastąp kod następującym fragmentem kodu:
namespace Notes.Views; public partial class AllNotesPage : ContentPage { public AllNotesPage() { InitializeComponent(); } }
Uruchom aplikację
Teraz możesz uruchomić aplikację i wszystko działa. Istnieją jednak dwa problemy z zachowaniem aplikacji:
- Jeśli wybierzesz notatkę, która otworzy edytor, naciśnij przycisk Zapisz, a następnie spróbujesz wybrać tę samą notatkę, nie działa.
- Za każdym razem, gdy notatka zostanie zmieniona lub dodana, lista notatek nie zostanie zmieniona w celu wyświetlenia najnowszych notatek u góry.
Te dwa problemy zostały rozwiązane w następnym kroku samouczka.
Naprawianie zachowania aplikacji
Teraz, gdy kod aplikacji może zostać skompilowany i uruchomiony, prawdopodobnie zauważysz, że istnieją dwie wady dotyczące zachowania aplikacji. Aplikacja nie umożliwia ponownego zaznaczenia notatki, która jest już zaznaczona, a lista notatek nie jest zmieniana po utworzeniu lub zmianie notatek.
Pobieranie notatek na początku listy
Najpierw rozwiąż problem z zmienianiem kolejności na liście notatek. W pliku ViewModels\NotesViewModel.cs kolekcja zawiera wszystkie notatki, AllNotes
które mają być prezentowane użytkownikowi. Niestety, wadą korzystania z elementu ObservableCollection
jest to, że musi być ręcznie posortowany. Aby pobrać nowe lub zaktualizowane elementy na początku listy, wykonaj następujące kroki:
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję ViewModels\NotesViewModel.cs.
W metodzie przyjrzyj
ApplyQueryAttributes
się logice zapisanego klucza ciągu zapytania.Gdy element
matchedNote
nienull
jest wartością , notatka jest aktualizowana.AllNotes.Move
Użyj metody , aby przenieść indeks do indeksumatchedNote
0, który jest górną częścią listy.string noteId = query["saved"].ToString(); NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault(); // If note is found, update it if (matchedNote != null) { matchedNote.Reload(); AllNotes.Move(AllNotes.IndexOf(matchedNote), 0); }
Metoda
AllNotes.Move
przyjmuje dwa parametry, aby przenieść położenie obiektu w kolekcji. Pierwszy parametr jest indeksem obiektu, który ma być przeniesiony, a drugi parametr jest indeksem, gdzie przenieść obiekt. MetodaAllNotes.IndexOf
pobiera indeks notatki.Gdy element
matchedNote
tonull
, notatka jest nowa i jest dodawana do listy. Zamiast dodawać ją, która dołącza notatkę na końcu listy, wstaw notatkę w indeksie 0, która jest górną częścią listy. Zmień metodę naAllNotes.Add
AllNotes.Insert
.string noteId = query["saved"].ToString(); NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault(); // If note is found, update it if (matchedNote != null) { matchedNote.Reload(); AllNotes.Move(AllNotes.IndexOf(matchedNote), 0); } // If note isn't found, it's new; add it. else AllNotes.Insert(0, new NoteViewModel(Models.Note.Load(noteId)));
Metoda ApplyQueryAttributes
powinna wyglądać podobnie do następującego fragmentu kodu:
void IQueryAttributable.ApplyQueryAttributes(IDictionary<string, object> query)
{
if (query.ContainsKey("deleted"))
{
string noteId = query["deleted"].ToString();
NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault();
// If note exists, delete it
if (matchedNote != null)
AllNotes.Remove(matchedNote);
}
else if (query.ContainsKey("saved"))
{
string noteId = query["saved"].ToString();
NoteViewModel matchedNote = AllNotes.Where((n) => n.Identifier == noteId).FirstOrDefault();
// If note is found, update it
if (matchedNote != null)
{
matchedNote.Reload();
AllNotes.Move(AllNotes.IndexOf(matchedNote), 0);
}
// If note isn't found, it's new; add it.
else
AllNotes.Insert(0, new NoteViewModel(Models.Note.Load(noteId)));
}
}
Zezwalaj na dwukrotne wybieranie notatki
W widoku AllNotes zostanie CollectionView
wyświetlona lista wszystkich notatek, ale nie pozwala na dwukrotne wybranie tej samej notatki. Istnieją dwa sposoby wybierania elementu: gdy użytkownik zmieni istniejącą notatkę, a kiedy użytkownik przymusowo przechodzi do tyłu. Przypadek, w którym użytkownik zapisuje notatkę, jest naprawiony ze zmianą kodu w poprzedniej sekcji, która używa AllNotes.Move
metody , więc nie musisz martwić się o ten przypadek.
Problem, który należy rozwiązać, jest teraz związany z nawigacją. Bez względu na sposób przechodzenia do widoku Wszystkie przypisy zdarzenie NavigatedTo
jest zgłaszane dla strony. To zdarzenie jest idealnym miejscem do wymuszonego usunięcia zaznaczenia wybranego elementu w elemencie CollectionView
.
Jednak w przypadku zastosowania wzorca MVVM model widoku nie może wyzwolić czegoś bezpośrednio w widoku, takiego jak wyczyszczenie wybranego elementu po zapisaniu notatki. Więc jak to zrobić? Dobra implementacja wzorca MVVM minimalizuje kod w widoku. Istnieje kilka różnych sposobów rozwiązania tego problemu w celu obsługi wzorca separacji MVVM. Jednak można również umieścić kod w kodzie w widoku, szczególnie wtedy, gdy jest on bezpośrednio powiązany z widokiem. MvVM ma wiele wspaniałych projektów i pojęć, które ułatwiają podział aplikacji, poprawę łatwości konserwacji i ułatwienie dodawania nowych funkcji. Jednak w niektórych przypadkach może się okazać, że MVVM zachęca do overengineering.
Nie overengineer rozwiązania tego problemu i po prostu użyj NavigatedTo
zdarzenia, aby wyczyścić wybrany element z .CollectionView
W okienku Eksplorator rozwiązań programu Visual Studio kliknij dwukrotnie pozycję Views\AllNotesPage.xaml.
W kodzie XAML dla
<ContentPage>
elementu dodajNavigatedTo
zdarzenie :<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewModels="clr-namespace:Notes.ViewModels" x:Class="Notes.Views.AllNotesPage" Title="Your Notes" NavigatedTo="ContentPage_NavigatedTo"> <ContentPage.BindingContext> <viewModels:NotesViewModel /> </ContentPage.BindingContext>
Możesz dodać domyślną procedurę obsługi zdarzeń, klikając prawym przyciskiem myszy nazwę metody zdarzenia,
ContentPage_NavigatedTo
i wybierając polecenie Przejdź do definicji. Ta akcja spowoduje otwarcie pliku Views\AllNotesPage.xaml.cs w edytorze kodu.Zastąp kod programu obsługi zdarzeń następującym fragmentem kodu:
private void ContentPage_NavigatedTo(object sender, NavigatedToEventArgs e) { notesCollection.SelectedItem = null; }
W języku XAML
CollectionView
element otrzymał nazwęnotesCollection
. Ten kod używa tej nazwy w celu uzyskania dostępu do elementu i ustawionegoCollectionView
SelectedItem
nanull
wartość . Zaznaczony element jest czyszczone za każdym razem, gdy strona zostanie wyświetlona.
Teraz uruchom aplikację. Spróbuj przejść do notatki, nacisnąć przycisk Wstecz i wybrać tę samą notatkę po raz drugi. Zachowanie aplikacji zostało naprawione!
Zapoznaj się z kodem tego samouczka. Jeśli chcesz pobrać kopię ukończonego projektu, aby porównać kod z, pobierz ten projekt.
Gratulacje!
Twoja aplikacja używa teraz wzorców MVVM!
Następne kroki
Poniższe linki zawierają więcej informacji związanych z niektórymi pojęciami poznanymi w tym samouczku:
Widzisz problem w tej sekcji? W takim przypadku prześlij opinię, abyśmy mogli udoskonalić tę sekcję.