Udostępnij za pośrednictwem


Dodawanie widoku i modelu notatki

W tej części samouczka przedstawiono pojęcia dotyczące widoków i modeli danych.

W poprzednich krokach samouczka dodano nową stronę do project, która umożliwia użytkownikowi zapisywanie, edytowanie lub usuwanie pojedynczej notatki. Jednak ponieważ aplikacja musi obsługiwać więcej niż jedną notatkę, musisz dodać kolejną stronę, która wyświetla wszystkie notatki (wywołaj ją AllNotesPage). Ta strona pozwala użytkownikowi wybrać notatkę do otwarcia na stronie edytora, aby móc wyświetlać, edytować lub usuwać. Powinno również umożliwić użytkownikowi utworzenie nowej notatki.

Aby to osiągnąć, AllNotesPage musi mieć kolekcję notatek i sposób wyświetlania kolekcji. W tym miejscu aplikacja ma problemy, ponieważ dane notatek są ściśle powiązane z plikiem NotePage . W AllNotesPageprogramie po prostu chcesz wyświetlić wszystkie notatki na liście lub w innym widoku kolekcji z informacjami o każdej notatce, na przykład datą utworzenia i podglądem tekstu. Ze względu na to, że tekst notatki jest ściśle powiązany z kontrolką TextBox, nie ma możliwości to do.

Przed dodaniem strony w celu wyświetlenia wszystkich notatek wprowadźmy pewne zmiany, aby oddzielić dane notatki od prezentacji notatki.

Widoki i modele

Zazwyczaj aplikacja WinUI 3 ma co najmniej warstwę widoku i warstwę danych.

Warstwa widoku definiuje interfejs użytkownika przy użyciu znaczników XAML. Znacznik zawiera wyrażenia związków danych (takie jak x:Bind), które definiują połączenie między określonymi składnikami interfejsu użytkownika a członkami danych. Pliki związane z kodem są czasami używane jako część warstwy widoku, aby zawierać dodatkowy kod potrzebny do dostosowania interfejsu użytkownika lub manipulowania nim albo wyodrębniania danych z argumentów procedury obsługi zdarzeń przed wywołaniem metody wykonującej pracę nad danymi.

Warstwa danych lub model definiuje typy reprezentujące dane aplikacji i powiązaną logikę. Ta warstwa jest niezależna od warstwy widoku i można utworzyć wiele różnych widoków, które współdziałają z danymi.

Obecnie obiekt NotePage reprezentuje widok danych (tekst notatki). Jednak po odczytaniu danych do aplikacji z pliku systemowego istnieje tylko we Text właściwości TextBox w NotePage. Nie jest ona reprezentowana w aplikacji w sposób umożliwiający prezentowanie danych na różne sposoby lub w różnych miejscach; oznacza to, że aplikacja nie ma warstwy danych. Teraz zrestrukturyzujesz project, aby utworzyć warstwę danych.

Oddzielanie widoku i modelu

Wskazówka

Możesz pobrać lub wyświetlić kod tego samouczka z repozytorium GitHub. Aby zobaczyć kod w tym kroku, zobacz ten commit: note page - view-model.

Refaktoryzuj istniejący kod, aby oddzielić model od widoku. W następnych kilku krokach zostanie zorganizowany kod, tak aby widoki i modele zostały zdefiniowane oddzielnie od siebie.

  1. W Solution Explorer kliknij prawym przyciskiem myszy WinUINotes project i wybierz Add>Nowy folder. Nadaj folderowi Modelsnazwę .

  2. Ponownie kliknij prawym przyciskiem myszy WinUINotes project i wybierz Dodaj>Nowy folder. Nadaj folderowi Viewsnazwę .

  3. NotePage.xaml Znajdź element i przeciągnij go do Views folderu. Plik NotePage.xaml.cs powinien zostać przeniesiony razem z nim.

    Uwaga / Notatka

    Podczas przenoszenia pliku Visual Studio zwykle wyświetla ostrzeżenie o tym, jak operacja przenoszenia może zająć dużo czasu. Nie powinno to być problemem w tym miejscu, naciśnij przycisk OK , jeśli widzisz to ostrzeżenie.

    Visual Studio może również zapytać, czy chcesz dostosować przestrzeń nazw przeniesionego pliku. Wybierz pozycję Nie. Przestrzeń nazw zmienisz w następnych krokach.

Aktualizowanie przestrzeni nazw widoku

Teraz, gdy widok został przeniesiony do Views folderu, musisz zaktualizować przestrzenie nazw, aby były zgodne. Przestrzeń nazw dla plików XAML i plików zaplecza kodowego stron jest ustawiona na wartość WinUINotes. Należy to zaktualizować do WinUINotes.Views.

  1. W okienku Solution Explorer rozwiń węzeł NotePage.xaml, aby wyświetlić plik za pomocą kodu.

  2. Kliknij dwukrotnie element, NotePage.xaml.cs aby otworzyć edytor kodu, jeśli nie jest jeszcze otwarty. Zmień przestrzeń nazw na WinUINotes.Views:

    namespace WinUINotes.Views
    
  3. Kliknij dwukrotnie element, NotePage.xaml aby otworzyć edytor XAML, jeśli nie jest jeszcze otwarty. Stara przestrzeń nazw jest odwoływana za pomocą atrybutu x:Class, który określa typ klasy jako kod-behind dla XAML. Ten wpis nie jest tylko przestrzenią nazw, ale przestrzenią nazw z typem. Zmień wartość x:Class na WinUINotes.Views.NotePage.

    x:Class="WinUINotes.Views.NotePage"
    

Napraw odwołanie do przestrzeni nazw w MainWindow

W poprzednim kroku utworzono stronę notatki i zaktualizowano MainWindow.xaml, aby do niej nawigować. Pamiętaj, że został on zmapowany z użyciem odwzorowania przestrzeni nazw local:. Częstą praktyką jest mapowanie nazwy local do głównej przestrzeni nazw projektu, a szablon projektu Visual Studio już to robi za Ciebie (xmlns:local="using:WinUINotes"). Teraz, gdy strona została przeniesiona do nowej przestrzeni nazw, mapowanie typów w języku XAML jest teraz nieprawidłowe.

Na szczęście możesz w razie potrzeby dodać własne mapowania przestrzeni nazw. Musisz to zrobić, aby uzyskiwać dostęp do elementów w różnych folderach tworzonych w projekcie. Ta nowa przestrzeń nazw XAML będzie mapować na przestrzeń nazw WinUINotes.Views, więc nadaj jej nazwę views. Deklaracja powinna wyglądać podobnie do następującego atrybutu: xmlns:views="using:WinUINotes.Views".

  1. W okienku Solution Explorer kliknij dwukrotnie wpis MainWindow.xaml aby otworzyć go w edytorze XAML.

  2. Dodaj nowe mapowanie przestrzeni nazw w wierszu poniżej mapowania elementu local:

    xmlns:views="using:WinUINotes.Views"
    
  3. local Przestrzeń nazw XAML została użyta do ustawienia Frame.SourcePageType właściwości, więc zmień ją na views . Kod XAML powinien teraz wyglądać następująco:

    <Window
        x:Class="WinUINotes.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WinUINotes"
        xmlns:views="using:WinUINotes.Views"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="WinUI Notes">
    
        <!-- ... Unchanged XAML not shown. -->
    
            <Frame x:Name="rootFrame" Grid.Row="1"
                   SourcePageType="views:NotePage"/>
    
        <!-- ... Unchanged XAML not shown. -->
    
    </Window>
    
  4. Skompiluj i uruchom aplikację. Aplikacja powinna działać bez żadnych błędów kompilatora, a wszystko powinno nadal działać tak jak wcześniej.

Definiowanie modelu

Obecnie model (dane) jest osadzony w widoku notatek. Utworzysz nową klasę reprezentującą dane strony notatek:

  1. W okienku Solution Explorer kliknij prawym przyciskiem myszy folder Models i wybierz pozycję Add>Class... .

  2. Nadaj klasie Note.cs nazwę i naciśnij przycisk Dodaj. Plik Note.cs zostanie otwarty w edytorze kodu.

  3. Zastąp kod w pliku Note.cs tym kodem, który tworzy klasę public i dodaje właściwości i metody do obsługi notatki.

    using System;
    using System.Threading.Tasks;
    using Windows.Storage;
    
    namespace WinUINotes.Models
    {
        public class Note
        {
            private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
            public string Filename { get; set; } = string.Empty;
            public string Text { get; set; } = string.Empty;
            public DateTime Date { get; set; } = DateTime.Now;
    
            public Note()
            {
                Filename = "notes" + DateTime.Now.ToBinary().ToString() + ".txt";
            }
    
            public async Task SaveAsync()
            {
                // Save the note to a file.
                StorageFile noteFile = (StorageFile)await storageFolder.TryGetItemAsync(Filename);
                if (noteFile is null)
                {
                    noteFile = await storageFolder.CreateFileAsync(Filename, CreationCollisionOption.ReplaceExisting);
                }
                await FileIO.WriteTextAsync(noteFile, Text);
            }
    
            public async Task DeleteAsync()
            {
                // Delete the note from the file system.
                StorageFile noteFile = (StorageFile)await storageFolder.TryGetItemAsync(Filename);
                if (noteFile is not null)
                {
                    await noteFile.DeleteAsync();
                }
            }
        }
    }
    
  4. Zapisz plik.

Zauważysz, że ten kod jest bardzo podobny do kodu w NotePage.xaml.cs, z kilkoma zmianami i dodatkami.

Filename i Text zostały zmienione na public właściwości, a nowa Date właściwość została dodana.

Kod do zapisania i usunięcia plików został umieszczony w public metodach. Jest on w większości identyczny z kodem, którego używasz w obsłudze zdarzeń przycisku Click w NotePage, ale usunięto dodatkowy kod aktualizujący widok po usunięciu pliku. Nie jest to potrzebne w tym miejscu, ponieważ będziesz używać powiązania danych, aby zachować synchronizację modelu i widoku.

Te sygnatury metody asynchronicznej zwracają zadanie zamiast void. Klasa Task reprezentuje pojedynczą operację asynchroniczną, która nie zwraca wartości. Jeśli podpis metody nie wymaga voidmetody , podobnie jak w przypadku Click procedur obsługi zdarzeń, async metody powinny zwrócić wartość Task.

Nie będziesz już przechowywać odwołania do StorageFile, który przechowuje notatkę. Po prostu spróbuj pobrać plik, gdy będzie potrzebny do zapisania lub usunięcia.

W NotePage użyto symbolu zastępczego dla nazwy pliku: note.txt. Teraz, gdy aplikacja obsługuje więcej niż jedną notatkę, nazwy plików dla zapisanych notatek muszą być różne i unikatowe. Aby to zrobić, ustaw właściwość Filename w konstruktorze. Możesz użyć metody DateTime.ToBinary , aby utworzyć część nazwy pliku na podstawie bieżącej godziny i ustawić unikatowe nazwy plików. Wygenerowana nazwa pliku wygląda następująco: notes-8584626598945870392.txt.

Aktualizowanie strony notatki

Teraz możesz zaktualizować widok NotePage, aby użyć modelu danych Note i usunąć kod przeniesiony do modelu Note.

  1. Otwórz plik Views\NotePage.xaml.cs , jeśli nie jest jeszcze otwarty w edytorze.

  2. Po ostatniej instrukcji using w górnej części strony dodaj nową instrukcję using, aby dać swojemu kodowi dostęp do klas w folderze Models i przestrzeni nazw.

    using WinUINotes.Models;
    
  3. Usuń następujące wiersze z klasy:

    private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    private StorageFile? noteFile = null;
    private string fileName = "note.txt";
    
  4. Zamiast tego dodaj Note obiekt o nazwie noteModel w ich miejsce. Reprezentuje to dane notatek, które NotePage przedstawia jako widok.

    private Note? noteModel;
    
  5. Program obsługi zdarzeń nie jest już potrzebny NotePage_Loaded . Nie będziesz odczytywać tekstu bezpośrednio z pliku tekstowego do kontrolki TextBox. Zamiast tego tekst notatki będzie odczytywany do Note obiektów. Dodasz kod, gdy w późniejszym kroku dodasz AllNotesPage. Usuń te wiersze.

    Loaded += NotePage_Loaded;
    
    ...
    
    private async void NotePage_Loaded(object sender, RoutedEventArgs e)
    {
        noteFile = (StorageFile)await storageFolder.TryGetItemAsync(fileName);
        if (noteFile is not null)
        {
          NoteEditor.Text = await FileIO.ReadTextAsync(noteFile);
        }
    }
    
  6. Zastąp kod w metodzie SaveButton_Click następującym kodem:

    if (noteModel is not null)
    {
        await noteModel.SaveAsync();
    }
    
  7. Zastąp kod w metodzie DeleteButton_Click następującym kodem:

    if (noteModel is not null)
    {
        await noteModel.DeleteAsync();
    }
    

Teraz możesz zaktualizować plik XAML, aby użyć Note modelu. Wcześniej odczytano tekst bezpośrednio z pliku tekstowego do właściwości w pliku code-behind. Teraz używasz powiązania danych dla Text właściwości .

  1. Otwórz plik Views\NotePage.xaml , jeśli nie jest jeszcze otwarty w edytorze.

  2. Text Dodaj atrybut do kontrolkiTextBox. Powiąż ją z właściwością Text: noteModelText="{x:Bind noteModel.Text, Mode=TwoWay}".

  3. Zaktualizuj Header, aby powiązać z właściwością Date elementu noteModel: Header="{x:Bind noteModel.Date.ToString()}".

    <TextBox x:Name="NoteEditor"
             <!-- ↓ Add this line. ↓ -->
             Text="{x:Bind noteModel.Text, Mode=TwoWay}"
             AcceptsReturn="True"
             TextWrapping="Wrap"
             PlaceholderText="Enter your note"
             <!-- ↓ Update this line. ↓ -->
             Header="{x:Bind noteModel.Date.ToString()}"
             ScrollViewer.VerticalScrollBarVisibility="Auto"
             Width="400"
             Grid.Column="1"/>
    

Powiązanie danych to sposób, aby interfejs użytkownika aplikacji wyświetlał dane i opcjonalnie pozostaje zsynchronizowany z danymi. Ustawienie Mode=TwoWay w powiązaniu oznacza, że właściwości TextBox.Text i noteModel.Text są automatycznie synchronizowane. Gdy tekst zostanie zaktualizowany w TextBox obiekcie, zmiany zostaną odzwierciedlone we właściwości TextnoteModel, a jeśli noteModel.Text zostanie zmieniona, aktualizacje zostaną odzwierciedlone w obiekcie TextBox.

Właściwość Header używa wartości domyślnej Mode , OneTime ponieważ noteModel.Date właściwość nie zmienia się po utworzeniu pliku. Ten kod demonstruje również zaawansowaną funkcję x:Bind o nazwie powiązanie funkcji, która umożliwia użycie funkcji, takiej jak ToString, jako krok w ścieżce powiązania.

Ważne

Ważne jest, aby wybrać prawidłowy BindingMode; w przeciwnym razie powiązanie danych może nie działać zgodnie z oczekiwaniami. (Typowym błędem z {x:Bind} jest zapominanie o zmianie wartości domyślnej BindingMode, gdy OneWay lub TwoWay jest to konieczne.)

Name Description
OneTime Aktualizuje właściwość docelową tylko po utworzeniu powiązania. Wartość domyślna dla {x:Bind}.
OneWay Aktualizuje właściwość docelową podczas tworzenia powiązania. Zmiany obiektu źródłowego mogą również być propagowane do obiektu docelowego. Wartość domyślna dla {Binding}.
TwoWay Aktualizuje obiekt docelowy lub obiekt źródłowy po zmianie. Po utworzeniu powiązania właściwość docelowa zostanie zaktualizowana ze źródła.

Powiązanie danych obsługuje rozdzielenie danych i interfejsu użytkownika oraz zapewnia prostszy model koncepcyjny, a także lepszą czytelność, możliwość testowania i konserwację aplikacji.

W systemie WinUI istnieją dwa rodzaje powiązań, spośród których można wybrać:

  • {x:Bind} rozszerzenie znaczników jest przetwarzane podczas kompilacji. Niektóre z jego zalet są ulepszone wydajność i sprawdzanie poprawności w czasie kompilacji wyrażeń powiązań. Zaleca się stosowanie wiązania danych w aplikacjach WinUI.
  • Rozszerzenie znaczników {Binding} jest przetwarzane w czasie wykonywania i wykorzystuje ogólną inspekcję obiektów w czasie wykonywania.

Dowiedz się więcej w dokumentacji:

Powiązanie danych i MVVM

Model-View-ViewModel (MVVM) to wzorzec projektowania architektonicznego interfejsu użytkownika, który oddziela kod interfejsu użytkownika od kodu bez interfejsu użytkownika, popularny wśród deweloperów .NET. Prawdopodobnie zobaczysz ją i usłyszysz, gdy dowiesz się więcej o tworzeniu aplikacji WinUI. Oddzielenie widoków i modeli, tak jak to zrobiłeś tutaj, jest pierwszym krokiem w kierunku pełnej implementacji MVVM aplikacji, ale na tym zakończy się ten samouczek.

Uwaga / Notatka

Użyliśmy terminu "model" do odwoływania się do modelu danych w tym samouczku, ale należy pamiętać, że ten model jest ściślej dopasowany do modelu ViewModel w pełnej implementacji MVVM, a także uwzględnia aspekty modelu.

Aby dowiedzieć się więcej o wzorcu MVVM, zapoznaj się z następującymi zasobami: