Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой части руководства представлены основные понятия представлений и моделей данных.
В предыдущих шагах руководства вы добавили новую страницу в project, которая позволяет пользователю сохранять, редактировать или удалять одну заметку. Необходимо добавить ещё одну страницу, отображающую все заметки (назовите её AllNotesPage), так как приложение должно работать с более чем одной заметкой. Эта страница позволяет пользователю выбрать заметку, открываемую на странице редактора, чтобы они могли просматривать, редактировать или удалять ее. Он также должен позволить пользователю создать новую заметку.
Для этого AllNotesPage необходимо иметь коллекцию заметок и способ отображения коллекции. Здесь приложение сталкивается с проблемами, поскольку данные заметок тесно привязаны к файлу NotePage. В AllNotesPageэтом случае вы просто хотите отобразить все заметки в списке или другом представлении коллекции с информацией о каждой заметке, например дате ее создания и предварительном просмотре текста. Если текст заметки тесно привязан к элементу управления TextBox, невозможно сделать это.
Перед добавлением страницы для отображения всех заметок давайте внесите некоторые изменения, чтобы разделить данные заметки от презентации заметки.
Представления и модели
Как правило, приложение WinUI 3 имеет по крайней мере слой представления и слой данных.
Слой представления определяет пользовательский интерфейс с помощью разметки XAML. Разметка включает выражения привязки данных (например, x:Bind), определяющие соединение между определенными компонентами пользовательского интерфейса и элементами данных. Файлы программной части иногда используются как часть слоя представления, чтобы содержать дополнительный код, необходимый для настройки пользовательского интерфейса или для извлечения данных из аргументов обработчика событий перед вызовом метода, выполняющего работу с данными.
Уровень данных или модель определяют типы, представляющие данные приложения и связанную логику. Этот слой не зависит от слоя представления, и вы можете создать несколько различных представлений, взаимодействующих с данными.
В настоящее время NotePage представляет собой представление данных (текст заметки). Однако после того, как данные считываются в приложение из системного файла, они существуют только в свойстве Text, в TextBoxNotePage. Он не представлен в приложении таким образом, что позволяет представлять данные различными способами или в разных местах; То есть приложение не имеет уровня данных. Теперь вы будете переструктурировать проект для создания слоя данных.
Разделите представление и модель
Подсказка
Вы можете скачать или просмотреть код для этого руководства из репозитория GitHub. Чтобы просмотреть код на этом этапе, см. этот коммит: note page - view-model.
Рефакторинг существующего кода для разделения модели от представления. Следующие несколько шагов упорядочит код таким образом, чтобы представления и модели были определены отдельно друг от друга.
В Solution Explorer щелкните правой кнопкой мыши папку WinUINotes project и выберите Add>New Folder. Назовите папку Models.
Щелкните правой кнопкой мыши на WinUINotes проекте еще раз и выберите Добавить>Новая папка. Назовите папку Views.
NotePage.xaml Найдите элемент и перетащите его в папкуViews. Файл NotePage.xaml.cs должен перемещаться вместе с ним.
Замечание
При перемещении файла Visual Studio обычно запрашивает предупреждение о том, как операция перемещения может занять много времени. Это не должно быть проблемой здесь, нажмите кнопку ОК , если вы видите это предупреждение.
Visual Studio также может попросить вас настроить пространство имен перемещаемого файла. Нажмите кнопку "Нет". Вы измените пространство имен в следующих шагах.
Обновление пространства имен представления
Теперь, когда представление перемещено в папку Views, необходимо обновить пространства имен, чтобы они соответствовали. Пространство имен для файлов XAML и файлов с кодом страниц установлено на WinUINotes. Это необходимо обновить до WinUINotes.Views.
В области Solution Explorer разверните NotePage.xaml, чтобы открыть файл кода.
Дважды щелкните NotePage.xaml.cs элемент, чтобы открыть редактор кода, если он еще не открыт. Измените пространство имен на
WinUINotes.Views:namespace WinUINotes.ViewsДважды щелкните 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"
В области Solution Explorer дважды щелкните запись MainWindow.xaml, чтобы открыть ее в редакторе XAML.
Добавьте это новое сопоставление пространства имен в строке ниже сопоставления для
local.xmlns:views="using:WinUINotes.Views"Пространство имен
localXAML использовалось для задания свойства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>Создайте и запустите приложение. Приложение должно выполняться без ошибок компилятора, и все должно работать как раньше.
Определение модели
В настоящее время модель (данные) внедрена в представление заметок. Вы создадите новый класс для представления данных страницы заметок:
В области Solution Explorer щелкните правой кнопкой мыши папку Models /> и выберите Add>Class... .
Назовите класс Note.cs и нажмите клавишу Add. Файл Note.cs откроется в редакторе кода.
Замените код в 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(); } } } }Сохраните файл.
Вы заметите, что этот код очень похож на код в NotePage.xaml.cs, с несколькими изменениями и дополнениями.
Filename и Text были изменены на public свойства, и добавлено новое Date свойство.
Код для сохранения и удаления файлов был помещен в public методы. В основном он идентичен коду, используемому в обработчиках событий кнопки ClickNotePage, но дополнительный код для обновления представления после удаления файла был удален. Здесь не требуется, так как вы будете использовать привязку данных для синхронизации модели и просмотра.
Эти асинхронные подписи методов возвращают задачу вместо void. Класс Task представляет одну асинхронную операцию, которая не возвращает значение. Если только сигнатура метода не требует void, как это в случае с обработчиками событий Click, методы async должны возвращать Task.
Вы также больше не будете хранить ссылку на StorageFile, который содержит заметку. Вы получаете файл только тогда, когда вам нужно его сохранить или удалить.
В NotePage файле использовался плейсхолдер для имени файла: note.txt Теперь, когда приложение поддерживает несколько заметок, имена файлов для сохраненных заметок должны быть разными и уникальными. Чтобы сделать это, задайте свойство Filename в конструкторе. Метод DateTime.ToBinary можно использовать для создания части имени файла на основе текущего времени и создания уникальных имен файлов. Имя созданного файла выглядит следующим образом: notes-8584626598945870392.txt
Обновление страницы заметок
Теперь вы можете обновить NotePage представление, чтобы использовать Note модель данных и удалить код, который был перемещен в Note модель.
Откройте файл Views\NotePage.xaml.cs , если он еще не открыт в редакторе.
После последней инструкции
usingв верхней части страницы добавьте новый операторusingдля того, чтобы дать вашему коду доступ к классам в папкеModelsи пространстве имен.using WinUINotes.Models;Удалите эти строки из класса:
private StorageFolder storageFolder = ApplicationData.Current.LocalFolder; private StorageFile? noteFile = null; private string fileName = "note.txt";Вместо этого добавьте объект
Noteс именемnoteModelна их место. Это представляет собой данные заметок, которыеNotePageпредоставляет представление о.private Note? noteModel;Кроме того, вам больше не нужен обработчик событий
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); } }Замените код в методе
SaveButton_Clickследующим образом:if (noteModel is not null) { await noteModel.SaveAsync(); }Замените код в методе
DeleteButton_Clickследующим образом:if (noteModel is not null) { await noteModel.DeleteAsync(); }
Теперь можно обновить XAML-файл, чтобы использовать Note модель. Ранее вы считывали текст непосредственно из текстового файла в свойство TextBox.Text в файл связанного кода. Теперь для Text свойства используется привязка данных.
Откройте файл Views\NotePage.xaml , если он еще не открыт в редакторе.
Добавьте атрибут
Textэлементу управленияTextBox. Привязать его к свойствуTextnoteModel:Text="{x:Bind noteModel.Text, Mode=TwoWay}".Обновите привязку
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.Text и noteModel.Text автоматически синхронизируются. Когда текст обновляется в TextBox, изменения отображаются в свойстве Text объекта 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 см. в следующих ресурсах:
Windows developer