Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой части руководства представлены основные понятия представлений и моделей данных.
В предыдущих шагах руководства вы добавили новую страницу в проект, которая позволяет пользователю сохранять, редактировать или удалять одну заметку. Тем не менее, так как приложение должно обрабатывать несколько заметок, необходимо добавить другую страницу, отображающую все заметки (вызвать его AllNotesPage). Эта страница позволит пользователю выбрать заметку, чтобы открыть ее на странице редактора, чтобы они могли просматривать, изменять или удалять их. Он также должен позволить пользователю создать новую заметку.
Для этого AllNotesPage необходимо иметь коллекцию заметок и способ отображения коллекции. Это место, когда приложение возникает с проблемами, так как данные заметок тесно привязаны к файлу NotePage . В AllNotesPageэтом случае вы просто хотите отобразить все заметки в списке или другом представлении коллекции с информацией о каждой заметке, например дате ее создания и предварительном просмотре текста. Если текст заметки тесно привязан к элементу TextBox управления, это невозможно сделать.
Перед добавлением страницы для отображения всех заметок давайте внесите некоторые изменения, чтобы разделить данные заметки от презентации заметки.
Представления и модели
Как правило, приложение WinUI имеет по крайней мере слой представления и слой данных.
Слой представления определяет пользовательский интерфейс с помощью разметки XAML. Разметка включает выражения привязки данных (например, x:Bind), определяющие соединение между определенными компонентами пользовательского интерфейса и элементами данных. Файлы программной части иногда используются как часть слоя представления, чтобы содержать дополнительный код, необходимый для настройки пользовательского интерфейса или для извлечения данных из аргументов обработчика событий перед вызовом метода, выполняющего работу с данными.
Уровень данных или модель определяют типы, представляющие данные приложения и связанную логику. Этот слой не зависит от слоя представления, и вы можете создать несколько различных представлений, взаимодействующих с данными.
В настоящее время представляет NotePage представление данных (текст заметки). Однако после того, как данные считываются в приложение из системного файла, он существует только в Text свойстве in TextBoxNotePage. Он не представлен в приложении таким образом, что позволяет представлять данные различными способами или в разных местах; То есть приложение не имеет уровня данных. Теперь вы будете реструктурировать проект, чтобы создать слой данных.
Разделение представления и модели
Подсказка
Вы можете скачать или просмотреть код для этого руководства из репозитория GitHub. Чтобы увидеть код как на этом шаге, см. эту фиксацию: страница заметок — модель представления.
Рефакторинг существующего кода для разделения модели с представлением. Следующие несколько шагов упорядочит код таким образом, чтобы представления и модели были определены отдельно друг от друга.
В обозревателе решений щелкните проект правой WinUINotes кнопкой мыши и выберите команду "Добавить>новую папку". Назовите папку Models.
Щелкните проект правой WinUINotes кнопкой мыши и выберите команду "Добавить>новую папку". Назовите папку Views.
NotePage.xaml Найдите элемент и перетащите его в папкуViews. Файл NotePage.xaml.cs должен перемещаться вместе с ним.
Замечание
При перемещении файла Visual Studio обычно запрашивает предупреждение о том, как операция перемещения может занять много времени. Это не должно быть проблемой здесь, нажмите кнопку ОК , если вы видите это предупреждение.
Visual Studio также может попросить вас настроить пространство имен перемещаемого файла. Нажмите кнопку "Нет". Вы измените пространство имен в следующих шагах.
Обновление пространства имен представления
Теперь, когда представление было перемещено Views в папку, необходимо обновить пространства имен для сопоставления. Пространство имен для файлов XAML и кода для страниц имеет значение WinUINotes. Это необходимо обновить до WinUINotes.Views.
В области обозревателя решений разверните узел 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"
В области обозревателя решений дважды щелкните запись MainWindow.xaml , чтобы открыть ее в редакторе XAML.
Добавьте это новое сопоставление пространства имен в строке ниже сопоставления:
localxmlns:views="using:WinUINotes.Views"Пространство
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>Создайте и запустите приложение. Приложение должно выполняться без ошибок компилятора, и все должно работать как раньше.
Определение модели
В настоящее время модель (данные) внедрена в представление заметок. Вы создадите новый класс для представления данных страницы заметок:
В области Обозреватель решений щелкните папку правой кнопкой мыши Models и выберите "Добавить>класс...".
Назовите класс 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 представляет одну асинхронную операцию, которая не возвращает значение. Если для обработчиков событий не требуется voidClick сигнатура метода, 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.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 см. в следующих ресурсах:
Windows developer