Поделиться через


Добавление представления и модели для заметки

В этой части руководства представлены основные понятия представлений и моделей данных.

В предыдущих шагах руководства вы добавили новую страницу в проект, которая позволяет пользователю сохранять, редактировать или удалять одну заметку. Тем не менее, так как приложение должно обрабатывать несколько заметок, необходимо добавить другую страницу, отображающую все заметки (вызвать его AllNotesPage). Эта страница позволит пользователю выбрать заметку, чтобы открыть ее на странице редактора, чтобы они могли просматривать, изменять или удалять их. Он также должен позволить пользователю создать новую заметку.

Для этого AllNotesPage необходимо иметь коллекцию заметок и способ отображения коллекции. Это место, когда приложение возникает с проблемами, так как данные заметок тесно привязаны к файлу NotePage . В AllNotesPageэтом случае вы просто хотите отобразить все заметки в списке или другом представлении коллекции с информацией о каждой заметке, например дате ее создания и предварительном просмотре текста. Если текст заметки тесно привязан к элементу TextBox управления, это невозможно сделать.

Перед добавлением страницы для отображения всех заметок давайте внесите некоторые изменения, чтобы разделить данные заметки от презентации заметки.

Представления и модели

Как правило, приложение WinUI имеет по крайней мере слой представления и слой данных.

Слой представления определяет пользовательский интерфейс с помощью разметки XAML. Разметка включает выражения привязки данных (например, x:Bind), определяющие соединение между определенными компонентами пользовательского интерфейса и элементами данных. Файлы программной части иногда используются как часть слоя представления, чтобы содержать дополнительный код, необходимый для настройки пользовательского интерфейса или для извлечения данных из аргументов обработчика событий перед вызовом метода, выполняющего работу с данными.

Уровень данных или модель определяют типы, представляющие данные приложения и связанную логику. Этот слой не зависит от слоя представления, и вы можете создать несколько различных представлений, взаимодействующих с данными.

В настоящее время представляет NotePage представление данных (текст заметки). Однако после того, как данные считываются в приложение из системного файла, он существует только в Text свойстве in TextBoxNotePage. Он не представлен в приложении таким образом, что позволяет представлять данные различными способами или в разных местах; То есть приложение не имеет уровня данных. Теперь вы будете реструктурировать проект, чтобы создать слой данных.

Разделение представления и модели

Подсказка

Вы можете скачать или просмотреть код для этого руководства из репозитория GitHub. Чтобы увидеть код как на этом шаге, см. эту фиксацию: страница заметок — модель представления.

Рефакторинг существующего кода для разделения модели с представлением. Следующие несколько шагов упорядочит код таким образом, чтобы представления и модели были определены отдельно друг от друга.

  1. В обозревателе решений щелкните проект правой WinUINotes кнопкой мыши и выберите команду "Добавить>новую папку". Назовите папку Models.

  2. Щелкните проект правой WinUINotes кнопкой мыши и выберите команду "Добавить>новую папку". Назовите папку Views.

  3. NotePage.xaml Найдите элемент и перетащите его в папкуViews. Файл NotePage.xaml.cs должен перемещаться вместе с ним.

    Замечание

    При перемещении файла Visual Studio обычно запрашивает предупреждение о том, как операция перемещения может занять много времени. Это не должно быть проблемой здесь, нажмите кнопку ОК , если вы видите это предупреждение.

    Visual Studio также может попросить вас настроить пространство имен перемещаемого файла. Нажмите кнопку "Нет". Вы измените пространство имен в следующих шагах.

Обновление пространства имен представления

Теперь, когда представление было перемещено Views в папку, необходимо обновить пространства имен для сопоставления. Пространство имен для файлов XAML и кода для страниц имеет значение WinUINotes. Это необходимо обновить до WinUINotes.Views.

  1. В области обозревателя решений разверните узел NotePage.xaml , чтобы открыть файл программной части.

  2. Дважды щелкните NotePage.xaml.cs элемент, чтобы открыть редактор кода, если он еще не открыт. Измените пространство WinUINotes.Viewsимен на:

    namespace WinUINotes.Views
    
  3. Дважды щелкните NotePage.xaml элемент, чтобы открыть редактор XAML, если он еще не открыт. Старое пространство имен ссылается через x:Class атрибут, который определяет тип класса, который является кодом для XAML. Эта запись не только пространство имен, но пространство имен с типом. Измените значение x:Classна WinUINotes.Views.NotePage :

    x:Class="WinUINotes.Views.NotePage"
    

Исправлена ссылка на пространство имен в MainWindow

На предыдущем шаге вы создали страницу заметок и обновили MainWindow.xaml ее, чтобы перейти к ней. Помните, что оно сопоставлено с сопоставлением local: пространства имен. Обычно рекомендуется сопоставить имя local с корневым пространством имен проекта, а шаблон проекта Visual Studio уже делает это для вас (xmlns:local="using:WinUINotes"). Теперь, когда страница перемещена в новое пространство имен, сопоставление типов в XAML теперь недопустимо.

К счастью, вы можете добавить собственные сопоставления пространств имен по мере необходимости. Это необходимо сделать, чтобы получить доступ к элементам в разных папках, создаваемых в проекте. Это новое пространство имен XAML будет сопоставляться с пространством WinUINotes.Viewsимен , поэтому назовем его views. Объявление должно выглядеть следующим образом: xmlns:views="using:WinUINotes.Views"

  1. В области обозревателя решений дважды щелкните запись MainWindow.xaml , чтобы открыть ее в редакторе XAML.

  2. Добавьте это новое сопоставление пространства имен в строке ниже сопоставления:local

    xmlns:views="using:WinUINotes.Views"
    
  3. Пространство local имен XAML использовалось для задания Frame.SourcePageType свойства, поэтому измените его на views него. Теперь xaml должен выглядеть следующим образом:

    <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. Создайте и запустите приложение. Приложение должно выполняться без ошибок компилятора, и все должно работать как раньше.

Определение модели

В настоящее время модель (данные) внедрена в представление заметок. Вы создадите новый класс для представления данных страницы заметок:

  1. В области Обозреватель решений щелкните папку правой кнопкой мыши Models и выберите "Добавить>класс...".

  2. Назовите класс Note.cs и нажмите клавишу Add. Файл Note.cs откроется в редакторе кода.

  3. Замените код в Note.cs файле этим кодом, который делает класс public и добавляет свойства и методы для обработки заметки:

    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. Сохраните файл.

Вы заметите, что этот код очень похож на код в NotePage.xaml.cs, с несколькими изменениями и дополнениями.

Filename и Text были изменены на public свойства, и добавлено новое Date свойство.

Код для сохранения и удаления файлов был помещен в public методы. В основном он идентичен коду, используемому в обработчиках событий кнопки ClickNotePage, но дополнительный код для обновления представления после удаления файла был удален. Здесь не требуется, так как вы будете использовать привязку данных для синхронизации модели и просмотра.

Эти асинхронные подписи методов возвращают задачу вместо void. Класс Task представляет одну асинхронную операцию, которая не возвращает значение. Если для обработчиков событий не требуется voidClick сигнатура метода, async методы должны возвращать Taskзначение.

Вы также не будете хранить ссылку на StorageFile заметку больше. Вы просто пытаетесь получить файл, когда нужно сохранить или удалить его.

В NotePageфайле использовался заполнитель для имени файла: note.txt Теперь, когда приложение поддерживает несколько заметок, имена файлов для сохраненных заметок должны быть разными и уникальными. Для этого задайте Filename свойство в конструкторе. Метод DateTime.ToBinary можно использовать для создания части имени файла на основе текущего времени и создания уникальных имен файлов. Имя созданного файла выглядит следующим образом: notes-8584626598945870392.txt

Обновление страницы заметок

Теперь вы можете обновить NotePage представление, чтобы использовать Note модель данных и удалить код, который был перемещен в Note модель.

  1. Откройте файл Views\NotePage.xaml.cs , если он еще не открыт в редакторе.

  2. После последней using инструкции в верхней части страницы добавьте новую using инструкцию, чтобы предоставить коду доступ к классам в папке Models и пространстве имен.

    using WinUINotes.Models;
    
  3. Удалите эти строки из класса:

    private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    private StorageFile? noteFile = null;
    private string fileName = "note.txt";
    
  4. Вместо этого добавьте Note объект с именем noteModel в их месте. Это представляет данные заметок, которые NotePage предоставляют представление.

    private Note? noteModel;
    
  5. Кроме того, обработчик событий больше не нужен NotePage_Loaded . Вы не будете читать текст непосредственно из текстового файла в TextBox. Вместо этого текст заметки будет считываться в Note объекты. Вы добавите код для этого при добавлении AllNotesPage на более позднем шаге. Удалите эти строки.

    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. Замените код в методе SaveButton_Click следующим образом:

    if (noteModel is not null)
    {
        await noteModel.SaveAsync();
    }
    
  7. Замените код в методе DeleteButton_Click следующим образом:

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

Теперь можно обновить XAML-файл, чтобы использовать Note модель. Ранее текст считывается непосредственно из текстового файла TextBox.Text в свойство в файле кода программной части. Теперь для Text свойства используется привязка данных.

  1. Откройте файл Views\NotePage.xaml , если он еще не открыт в редакторе.

  2. Text Добавьте атрибут в TextBox элемент управления. Привязать его к свойству TextnoteModel: Text="{x:Bind noteModel.Text, Mode=TwoWay}".

  3. Обновите привязку Header к свойству DatenoteModel : 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"/>
    

Привязка данных позволяет пользовательскому интерфейсу приложения отображать данные и, при необходимости, оставаться с ними синхронизированным. Параметр Mode=TwoWay привязки означает, что TextBox.TextnoteModel.Text свойства и свойства автоматически синхронизируются. Когда текст обновляется в объекте, изменения отражаются в TextBoxText свойстве объектаnoteModel, и при noteModel.Text изменении обновления отражаются в элементе TextBox.

Свойство Header использует значение по умолчанию ModeOneTime, так как noteModel.Date свойство не изменяется после создания файла. Этот код также демонстрирует мощную функцию x:Bind вызываемой привязки функций, которая позволяет использовать функцию, например ToString шаг в пути привязки.

Это важно

Важно выбрать правильный BindingMode; В противном случае привязка данных может не работать должным образом. (Распространенная ошибка заключается в {x:Bind} том, чтобы забыть изменить значение по умолчанию BindingMode при OneWayTwoWay необходимости.)

Имя Description
OneTime Обновляет целевое свойство только при создании привязки. Значение по умолчанию для {x:Bind}.
OneWay Обновляет целевое свойство при создании привязки. Изменения исходного объекта также могут распространяться на целевой объект. Значение по умолчанию для {Binding}.
TwoWay Обновляет целевой объект или исходный объект при изменении. При создании привязки целевое свойство обновляется из источника.

Привязка данных поддерживает разделение данных и пользовательского интерфейса, что приводит к более простой концептуальной модели, а также повышению удобочитаемости, тестируемости и поддержке вашего приложения.

В WinUI можно выбрать два типа привязки:

  • {x:Bind} Расширение разметки обрабатывается во время компиляции. Некоторые из его преимуществ повышают производительность и проверку времени компиляции выражений привязки. Рекомендуется выполнить привязку в приложениях WinUI.
  • {Binding} Расширение разметки обрабатывается во время выполнения и использует проверку объектов среды выполнения общего назначения.

Дополнительные сведения см. в документации:

Привязка данных и MVVM

Model-View-ViewModel (MVVM) — это шаблон архитектуры пользовательского интерфейса для развязывания пользовательского интерфейса и кода, отличного от пользовательского интерфейса, популярного для разработчиков .NET. Вероятно, вы увидите и услышите это, как вы узнаете больше о создании приложений WinUI. Разделение представлений и моделей, как вы уже сделали здесь, является первым шагом к полной реализации MVVM приложения, но это до сих пор, как вы пойдете в этом руководстве.

Замечание

Мы использовали термин "модель", чтобы ссылаться на модель данных в этом руководстве, но важно отметить, что эта модель более тесно согласована с ViewModel в полной реализации MVVM, а также включает аспекты модели.

Дополнительные сведения о MVVM см. в следующих ресурсах: