Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Если вы разработали пользовательский интерфейс с изображениями заполнителей и шаблонным текстом, в этом руководстве показано, как подключить его к реальным данным с помощью привязок данных. Узнайте, как отформатировать данные, сохранить пользовательский интерфейс и данные в синхронизации и повысить удобство обслуживания кода.
В этом руководстве вы узнаете, как заменить шаблон привязками данных и создать другие прямые связи между пользовательским интерфейсом и данными. Вы также узнаете, как отформатировать или преобразовать данные для отображения, а также сохранить пользовательский интерфейс и данные в синхронизации. По завершении работы с этим руководством вы можете улучшить простоту и организацию кода XAML и C#, что упрощает обслуживание и расширение.
Начните с упрощенной версии примера PhotoLab. Эта начальная версия включает полный уровень данных, а также базовые макеты страниц XAML и оставляет много функций, чтобы упростить обзор кода. В этом руководстве не создается полное приложение, поэтому обязательно ознакомьтесь с окончательной версией, чтобы увидеть такие функции, как пользовательские анимации и адаптивные макеты. Окончательную версию можно найти в корневой папке репозитория Windows-appsample-photo-lab.
Пример приложения PhotoLab содержит две страницы. На главной странице отображается представление коллекции фотографий, а также некоторые сведения о каждом файле изображения.
После выбора страницы сведений отображается одна фотография. Всплывающее меню редактирования позволяет изменять, переименовать и сохранять фотографию.
Предпосылки
- Visual Studio 2019 или более новая версия: Скачать Visual Studio (Выпуск Community является бесплатным.)
- Пакет SDK для Windows (10.0.17763.0 или более поздней версии): скачать последнюю версию пакета SDK для Windows (бесплатно)
- Windows 10 версии 1809 или более поздней
Часть 0. Получение начального кода с GitHub
В этом руководстве вы начинаете с упрощенной версии примера PhotoLab.
Перейдите на страницу GitHub для примера: https://github.com/Microsoft/Windows-appsample-photo-lab.
Затем необходимо клонировать или скачать пример. Нажмите кнопку Клонировать или скачать. Появляется вложенное меню.
Если вы не знакомы с GitHub:
a. Выберите Загрузить ZIP и сохраните файл локально. Это действие скачивает файл .zip, содержащий все необходимые файлы проекта.
б. Извлеките файл. Используйте Проводник файлов, чтобы перейти к файлу .zip, который вы только что скачали, щелкните правой кнопкой мыши и выберите Извлечь все....
с. Перейдите к локальной копии примера и перейдите в каталог
Windows-appsample-photo-lab-master\xaml-basics-starting-points\data-binding.Если вы знакомы с GitHub:
a. Клонируйте основную ветвь репозитория локально.
б. Перейдите к каталогу
Windows-appsample-photo-lab\xaml-basics-starting-points\data-binding.Дважды щелкните
Photolab.sln, чтобы открыть решение в Visual Studio.
Часть 1. Замена переменных
В этом разделе вы создадите одноразовые привязки в данном XAML-шаблоне для отображения реальных изображений и метаданных изображений вместо содержимого заполнителя.
Однократные привязки предназначены только для чтения неизменяемых данных. Они очень высокопроизводительны и просты в создании, поэтому вы можете отображать большие наборы данных в элементах управления GridView и ListView.
Замените заполнители единовременными привязками
Откройте папку
xaml-basics-starting-points\data-bindingи запустите файлPhotoLab.slnв Visual Studio.Убедитесь, что платформы решений
задано значение x86 или x64, а не Arm, а затем запустите приложение. На этом шаге показано состояние приложения с заполнителями пользовательского интерфейса перед добавлением привязок.
Откройте MainPage.xaml и найдите
DataTemplateс именем ImageGridView_DefaultItemTemplate. Вы обновите этот шаблон, чтобы использовать привязки данных.до:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate">Значение
x:KeyиспользуетсяImageGridViewдля выбора данного шаблона для отображения объектов данных.Добавьте значение
x:DataTypeв шаблон.после:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo">x:DataTypeуказывает, для какого типа используется этот шаблон. В этом случае это шаблон для классаImageFileInfo(гдеlocal:указывает локальное пространство имен, как определено в объявлении xmlns в верхней части файла).Вам нужен
x:DataType, если вы используете выраженияx:Bindв шаблоне данных, как описано ниже.В
DataTemplateнайдите элементImageс именемItemImageи замените его значениеSource, как показано ниже.до:
<Image x:Name="ItemImage" Source="/Assets/StoreLogo.png" Stretch="Uniform" />после:
<Image x:Name="ItemImage" Source="{x:Bind ImageSource}" Stretch="Uniform" />x:Nameидентифицирует элемент XAML, чтобы на него можно было ссылаться в другом месте в XAML и в коде.x:Bindвыражения предоставляют значение свойству пользовательского интерфейса, получая значение из свойства объекта данных. В шаблонах указанное свойство является свойством любогоx:DataTypeзаданного значения. Таким образом, в этом случае источник данных является свойствомImageFileInfo.ImageSource.Замечание
Значение
x:Bindтакже позволяет редактору знать о типе данных, поэтому вместо ввода имени свойства в выраженииx:Bindможно использовать IntelliSense. Попробуйте использовать код, который вы только что вставили: поместите курсор сразу послеx:Bindи нажмите пробел, чтобы просмотреть список свойств, к которые можно привязать.Замените значения других элементов управления пользовательским интерфейсом таким же образом. (Попробуйте сделать это с IntelliSense вместо копирования и вставки!)
до:
<TextBlock Text="Placeholder" ... /> <StackPanel ... > <TextBlock Text="PNG file" ... /> <TextBlock Text="50 x 50" ... /> </StackPanel> <muxc:RatingControl Value="3" ... />после:
<TextBlock Text="{x:Bind ImageTitle}" ... /> <StackPanel ... > <TextBlock Text="{x:Bind ImageFileType}" ... /> <TextBlock Text="{x:Bind ImageDimensions}" ... /> </StackPanel> <muxc:RatingControl Value="{x:Bind ImageRating}" ... />
Запустите приложение, чтобы узнать, как оно выглядит на данный момент. Больше никаких заполнителей! У тебя хороший старт.
Замечание
Если вы хотите дополнительно поэкспериментировать, попробуйте добавить новый TextBlock в шаблон данных и используйте трюк x:Bind IntelliSense для поиска свойства для отображения.
Часть 2. Использование привязки для подключения пользовательского интерфейса коллекции к изображениям
В этом разделе вы создадите однократные привязки на странице XAML для подключения представления галереи к коллекции изображений. Эти привязки заменяют существующий процедурный код в коде программной части. Вы также создадите кнопку "Удалить ", чтобы узнать, как представление коллекции изменяется при удалении изображений из коллекции. Одновременно вы узнаете, как привязывать события к обработчикам для большей гибкости по сравнению с традиционными методами.
Все привязки, описанные до сих пор, находятся внутри шаблонов данных и ссылаются на свойства класса, указанного значением x:DataType. А что с остальным XAML на вашей странице?
x:Bind выражения за пределами шаблонов данных всегда привязываются к самой странице. Это означает, что вы можете ссылаться на все, что вы помещаете в код или объявляете в XAML, включая пользовательские свойства и свойства других элементов управления пользовательского интерфейса на странице (если они имеют значение x:Name).
В примере PhotoLab вы используете такую привязку, чтобы подключить основной GridView элемент управления непосредственно к коллекции изображений, а не выполнять его в коде программной части. Позже вы увидите другие примеры.
Привязка основного элемента управления GridView к коллекции Изображений
В MainPage.xaml.cs найдите метод
GetItemsAsyncи удалите код, который задаетItemsSource.до:
ImageGridView.ItemsSource = Images;после:
// Replaced with XAML binding: // ImageGridView.ItemsSource = Images;В MainPage.xaml найдите
GridViewс именемImageGridViewи добавьте атрибутItemsSource. Для этого значения используйте выражениеx:Bind, ссылающееся на свойствоImages, реализованное в программном коде.до:
<GridView x:Name="ImageGridView"после:
<GridView x:Name="ImageGridView" ItemsSource="{x:Bind Images}"Свойство
Imagesимеет типObservableCollection<ImageFileInfo>, поэтому отдельные элементы, отображаемые вGridView, имеют типImageFileInfo. Этот тип соответствует значению, описанномуx:DataTypeв части 1.
Все привязки, которые вы видели ранее, являются однократными и доступными только для чтения привязками, что является поведением по умолчанию для простых x:Bind выражений. Данные загружаются только при инициализации, что обеспечивает привязки высокой производительности — это идеально подходит для поддержки нескольких сложных видов больших наборов данных.
Даже добавленная ItemsSource привязка — это однократная привязка только для чтения к неизменному значению свойства, но здесь есть важное различие. Неизменное значение свойства Images — это одиночный конкретный экземпляр коллекции, инициализированный один раз, как показано здесь.
private ObservableCollection<ImageFileInfo> Images { get; }
= new ObservableCollection<ImageFileInfo>();
Images Значение свойства никогда не изменяется, но так как свойство имеет типObservableCollection<T>, содержимое коллекции может изменяться, а привязка автоматически замечает изменения и обновляет пользовательский интерфейс.
Чтобы проверить это поведение, временно добавьте кнопку, которая удаляет выбранное изображение. Эта кнопка не отображается в окончательной версии, так как при выборе изображения вы перейдете на страницу сведений. Однако поведение ObservableCollection<T> по-прежнему важно в последнем примере PhotoLab, так как XAML инициализируется в конструкторе страниц (с помощью вызова метода InitializeComponent), но коллекция Images заполняется позже в методе GetItemsAsync.
Кнопка "Удалить"
В Файле MainPage.xaml найдите
CommandBarс именем MainCommandBar и добавьте новую кнопку перед кнопкой масштабирования. (Элементы управления масштабированием еще не работают. Вы подключитесь к ним в следующей части руководства.)<AppBarButton Icon="Delete" Label="Delete selected image" Click="{x:Bind DeleteSelectedImage}" />Если вы уже знакомы с XAML, это
Clickзначение может выглядеть необычно. В предыдущих версиях XAML необходимо задать этот метод с определенной сигнатурой обработчика событий, обычно включая параметры отправителя события и объекта аргументов для конкретного события. Этот метод по-прежнему можно использовать при необходимости аргументов событий, но с помощьюx:Bind, вы также можете подключиться к другим методам. Например, если вам не нужны данные события, можно подключиться к методам, не имеющим параметров, как и здесь.В MainPage.xaml.cs добавьте метод
DeleteSelectedImage.private void DeleteSelectedImage() => Images.Remove(ImageGridView.SelectedItem as ImageFileInfo);Этот метод просто удаляет выбранный образ из коллекции
Images.
Теперь запустите приложение и нажмите кнопку для удаления нескольких изображений. Как видно, пользовательский интерфейс обновляется автоматически, благодаря привязке данных и типу ObservableCollection<T>.
Замечание
Этот код удаляет только экземпляр ImageFileInfo из коллекции Images в работающем приложении. Он не удаляет файл изображения с компьютера.
Часть 3. Настройка ползунка масштабирования
В этой части вы создадите односторонние привязки из элемента управления в шаблоне данных к ползунку масштабирования за пределами шаблона. Вы также узнаете, что можно использовать привязку данных со многими свойствами элемента управления, а не только с наиболее очевидными, такими как TextBlock.Text и Image.Source.
Привязка шаблона данных изображения к ползунку масштабирования
Найдите
DataTemplateс именемImageGridView_DefaultItemTemplateи замените значения**Height**иWidthэлемента управленияGridв верхней части шаблона.До
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="200" Width="200" Margin="{StaticResource LargeItemMargin}">После
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding Value, ElementName=ZoomSlider}" Width="{Binding Value, ElementName=ZoomSlider}" Margin="{StaticResource LargeItemMargin}">
Вы заметили, что это Binding выражения, а не x:Bind выражения? Это старый способ выполнения привязок данных, и он в основном устарел.
x:Bind делает почти все, что Binding делает, и многое другое. Однако при использовании x:Bind в шаблоне данных он привязывается к типу, объявленному в значении x:DataType. Таким образом, как привязать что-то в шаблоне к чему-то на странице XAML или в коде программной части? Необходимо использовать устаревшее выражение Binding.
Binding выражения не распознают значение x:DataType, но эти Binding выражения имеют ElementName значения, которые работают почти так же. Они сообщают механизму привязки, что значение привязки является привязкой к свойству Value указанного элемента на странице (то есть элемента с этим значением x:Name). Если вы хотите привязаться к свойству в фоновом коде, это будет выглядеть примерно как {Binding MyCodeBehindProperty, ElementName=page}, где page обращается к значению x:Name, заданному в элементе Page в XAML.
Замечание
По умолчанию Binding выражения — это односторонние, то есть они автоматически обновляют данные в интерфейсе при изменении значения привязанного свойства.
В отличие от этого, по умолчанию для x:Bind используется однократноевремя, что означает, что любые изменения в связанном свойстве игнорируются. Это по умолчанию, так как это самый высокопроизводительный вариант, и большинство привязок относятся к статическим, доступным только для чтения данным.
В этом уроке показано, что если вы используете x:Bind со свойствами, которые могут изменить их значения, обязательно добавьте Mode=OneWay или Mode=TwoWay. Примеры этого вы увидите в следующем разделе.
Запустите приложение и используйте ползунок для изменения измерений шаблона изображения. Как видите, эффект довольно мощный, не нуждаясь в большом коде.
Замечание
Чтобы испытать себя, попробуйте привязать другие свойства пользовательского интерфейса к свойству ползунка масштабирования Value или к другим ползункам, добавленным после ползунка масштабирования. Например, можно привязать свойство FontSize элемента TitleTextBlock к новому ползунку со значением по умолчанию 24. Не забудьте задать разумные минимальные и максимальные значения.
Часть 4. Улучшение возможностей масштабирования
В этой части вы добавите пользовательское свойство ItemSize для заднего кода и создадите односторонние привязки из шаблона изображения к новому свойству. Значение ItemSize будет обновлено ползунком масштабирования и другими факторами, такими как переключателем Обрезка по экрану и размером окна, что создаёт более изысканный опыт.
В отличие от встроенных свойств элемента управления, ваши настраиваемые свойства не обновляют пользовательский интерфейс автоматически, даже с односторонней и двусторонней привязкой. Они работают хорошо с однимвремя привязки, но если вы хотите, чтобы изменения свойств на самом деле отображались в пользовательском интерфейсе, вам нужно выполнить некоторую работу.
Создайте свойство ItemSize, чтобы обновить пользовательский интерфейс
В MainPage.xaml.cs измените сигнатуру класса
MainPageтаким образом, чтобы он реализовал интерфейсINotifyPropertyChanged.до:
public sealed partial class MainPage : Pageпосле:
public sealed partial class MainPage : Page, INotifyPropertyChangedЭто сообщает системе привязки, что
MainPageимеет событиеPropertyChanged, которое будет добавлено далее и на которое могут подписываться привязки для обновления пользовательского интерфейса.Добавьте событие
PropertyChangedв классMainPage.public event PropertyChangedEventHandler PropertyChanged;Это событие обеспечивает полную реализацию, необходимую интерфейсом
INotifyPropertyChanged. Тем не менее, чтобы оно могло иметь какой-либо эффект, необходимо явно вызвать событие в пользовательских свойствах.Добавьте свойство
ItemSizeи вызовите событиеPropertyChangedв его методе установки.public double ItemSize { get => _itemSize; set { if (_itemSize != value) { _itemSize = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize))); } } } private double _itemSize;Свойство
ItemSizeпредоставляет значение частного поля_itemSize. При использовании резервного поля, подобного этому, свойство позволяет проверить, совпадает ли новое значение со старым значением, прежде чем оно вызывает потенциально ненужные событияPropertyChanged.Само событие вызывается методом
Invoke. Вопросительный знак проверяет, является ли событиеPropertyChangednull, то есть были ли добавлены какие-нибудь обработчики событий. Каждая односторонняя или двусторонняя привязка добавляет обработчик событий в скрытом режиме, но если здесь никто не слушает, ничего больше не произойдет. ЕслиPropertyChangedне имеет значения NULL, тоInvokeвызывается со ссылкой на источник событий (сама страница, представленная ключевым словомthis) и объект event-args, указывающий имя свойства. Эта информация позволит односторонним или двусторонним привязкам к свойствуItemSizeбыть в курсе всех изменений, чтобы они могли обновить привязанный пользовательский интерфейс.В MainPage.xaml найдите
DataTemplateс именемImageGridView_DefaultItemTemplateи замените значенияHeightиWidthэлемента управленияGridв верхней части шаблона. (Если вы выполняли привязку элементы управления к элементу управления в предыдущей части этого руководства, то единственными изменениями будут заменаValueнаItemSizeиZoomSliderнаpage. Не забудьте сделать это как дляHeight, так и дляWidth!)До
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding Value, ElementName=ZoomSlider}" Width="{Binding Value, ElementName=ZoomSlider}" Margin="{StaticResource LargeItemMargin}">После
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding ItemSize, ElementName=page}" Width="{Binding ItemSize, ElementName=page}" Margin="{StaticResource LargeItemMargin}">
Теперь, когда пользовательский интерфейс может реагировать на изменения ItemSize, необходимо действительно их внести. Как упоминалось ранее, значение ItemSize вычисляется из текущего состояния различных элементов управления пользовательским интерфейсом, но вычисление должно выполняться всякий раз, когда эти элементы управления изменяют состояние. Для этого вы будете использовать привязку событий, чтобы определенные изменения пользовательского интерфейса вызвали вспомогательный метод, который обновляет ItemSize.
Обновление значения свойства ItemSize
Добавьте метод
DetermineItemSizeдля MainPage.xaml.cs.private void DetermineItemSize() { if (FitScreenToggle != null && FitScreenToggle.IsOn == true && ImageGridView != null && ZoomSlider != null) { // The 'margins' value represents the total of the margins around the // image in the grid item. 8 from the ItemTemplate root grid + 8 from // the ItemContainerStyle * (Right + Left). If those values change, // this value needs to be updated to match. int margins = (int)this.Resources["LargeItemMarginValue"] * 4; double gridWidth = ImageGridView.ActualWidth - (int)this.Resources["DefaultWindowSidePaddingValue"]; double ItemWidth = ZoomSlider.Value + margins; // We need at least 1 column. int columns = (int)Math.Max(gridWidth / ItemWidth, 1); // Adjust the available grid width to account for margins around each item. double adjustedGridWidth = gridWidth - (columns * margins); ItemSize = (adjustedGridWidth / columns); } else { ItemSize = ZoomSlider.Value; } }В MainPage.xaml перейдите в начало файла и добавьте привязку события
SizeChangedк элементуPage.до:
<Page x:Name="page"после:
<Page x:Name="page" SizeChanged="{x:Bind DetermineItemSize}"Найдите
Sliderс именемZoomSlider(в разделеPage.Resources) и добавьте привязку событияValueChanged.до:
<Slider x:Name="ZoomSlider"после:
<Slider x:Name="ZoomSlider" ValueChanged="{x:Bind DetermineItemSize}"Найдите
ToggleSwitchс именемFitScreenToggleи добавьте привязку событийToggled.до:
<ToggleSwitch x:Name="FitScreenToggle"после:
<ToggleSwitch x:Name="FitScreenToggle" Toggled="{x:Bind DetermineItemSize}"
Запустите приложение и используйте ползунок масштабирования и Fit to screen переключатель, чтобы изменить размеры шаблона изображения. Как видно, последние изменения позволяют более подробно масштабировать или изменять размер, сохраняя код хорошо упорядоченным.
Замечание
Для испытания попробуйте добавить TextBlock после ZoomSlider и привязать свойство Text к свойству ItemSize. Так как он не находится в шаблоне данных, вы можете использовать x:Bind вместо Binding, как в предыдущих привязках ItemSize.
Часть 5. Включение правок пользователей
Здесь вы создадите двусторонние привязки, чтобы пользователи могли обновлять значения, включая название изображения, рейтинг и различные визуальные эффекты.
Для этого вы обновите существующую DetailPage, которая предоставляет средство просмотра одного изображения, элемент управления масштабированием и пользовательский интерфейс редактирования.
Сначала, однако, необходимо подключить DetailPage, чтобы приложение могло перейти к нему, когда пользователь кликает по изображению в представлении галереи.
Прикрепить страницу DetailPage
В Файле MainPage.xaml найдите
GridViewс именемImageGridView. Чтобы сделать элементы доступными для щелчка, задайте дляIsItemClickEnabledзначениеTrueи добавьте обработчик событийItemClick.Подсказка
Если ввести изменения ниже вместо копирования и вставки, появится всплывающее окно IntelliSense с надписью "<Новый обработчик событий>". Если нажать клавишу TAB, он будет заполнять значение именем обработчика методов по умолчанию и автоматически заглушить метод, показанный на следующем шаге. Затем можно нажать клавишу F12, чтобы перейти к методу в коде позади.
до:
<GridView x:Name="ImageGridView">после:
<GridView x:Name="ImageGridView" IsItemClickEnabled="True" ItemClick="ImageGridView_ItemClick">Замечание
Мы используем обычный обработчик событий вместо выражения x:Bind. Это связано с тем, что нам нужно просмотреть данные события, как показано далее.
В MainPage.xaml.cs добавьте обработчик событий (или заполните его, если вы использовали подсказку на последнем шаге).
private void ImageGridView_ItemClick(object sender, ItemClickEventArgs e) { this.Frame.Navigate(typeof(DetailPage), e.ClickedItem); }Этот метод просто переходит на детализированную страницу, передавая нажатый элемент, который является объектом
ImageFileInfo, используемым DetailPage.OnNavigatedTo для инициализации страницы. Вам не придется реализовывать этот метод в этом руководстве, но вы можете изучить, как он работает.(Необязательно) Удалите или закомментируйте все элементы управления, добавленные в предыдущие точки воспроизведения, которые работают с выбранным изображением. Сохранение их не повредит, но сейчас гораздо сложнее выбрать изображение, не перейдя на страницу подробностей.
Теперь, когда вы подключили две страницы, запустите приложение и посмотрите вокруг. Все работает, кроме элементов управления на панели редактирования, которые не отвечают при попытке изменить значения.
Как видно, текстовое поле заголовка отображает название и позволяет вводить изменения. Вам нужно изменить фокус на другой элемент управления, чтобы зафиксировать изменения, но заголовок в левом верхнем углу экрана еще не обновляется.
Все элементы управления уже привязаны с помощью простых x:Bind выражений, которые мы рассмотрели в части 1. Если вы помните, это означает, что они являются однократными привязками, что объясняет, почему изменения значений не регистрируются. Чтобы устранить эту проблему, все, что нам нужно сделать, заключается в том, чтобы превратить их в двусторонние привязки.
Создание интерактивных элементов управления редактированием
В DetailPage.xaml найдите
TextBlockс именем TitleTextBlock и контроль RatingControl после него, и обновите их выраженияx:Bind, чтобы включить Mode=TwoWay.до:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating}" ... >после:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle, Mode=TwoWay}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating, Mode=TwoWay}" ... >Сделайте то же самое для всех ползунков эффекта, которые приходят после элемента управления рейтингом.
<Slider Header="Exposure" ... Value="{x:Bind item.Exposure, Mode=TwoWay}" ... <Slider Header="Temperature" ... Value="{x:Bind item.Temperature, Mode=TwoWay}" ... <Slider Header="Tint" ... Value="{x:Bind item.Tint, Mode=TwoWay}" ... <Slider Header="Contrast" ... Value="{x:Bind item.Contrast, Mode=TwoWay}" ... <Slider Header="Saturation" ... Value="{x:Bind item.Saturation, Mode=TwoWay}" ... <Slider Header="Blur" ... Value="{x:Bind item.Blur, Mode=TwoWay}" ...
Двусторонний режим, как и ожидалось, означает, что данные перемещаются в обоих направлениях всякий раз, когда есть изменения на обеих сторонах.
Как и односторонние привязки, описанные ранее, эти двусторонние привязки теперь обновляют пользовательский интерфейс при изменении связанных свойств благодаря реализации INotifyPropertyChanged в классе ImageFileInfo. Однако при двусторонней привязке значения также будут перемещаться из пользовательского интерфейса в привязанные свойства, когда пользователь взаимодействует с элементом управления. Ничего больше не требуется на стороне XAML.
Запустите приложение и попробуйте элементы управления редактированием. Как видно, при внесении изменения он влияет на значения изображения, и эти изменения сохраняются при переходе на главную страницу.
Часть 6. Форматирование значений с помощью привязки функции
Одна последняя проблема остается. При перемещении ползунка эффектов метки рядом с ними по-прежнему не изменяются.
ползунки 
Последняя часть этого руководства заключается в добавлении привязок, которые форматируют значения ползунка для отображения.
Привязка меток слайдера эффектов и форматирование значений для отображения
Найдите
TextBlockпосле ползункаExposureи замените значениеTextвыражением привязки, показанным здесь.до:
<Slider Header="Exposure" ... /> <TextBlock ... Text="0.00" />после:
<Slider Header="Exposure" ... /> <TextBlock ... Text="{x:Bind item.Exposure.ToString('N', culture), Mode=OneWay}" />Это называется привязкой функции, так как вы привязываются к возвращаемого значения метода. Метод должен быть доступен через внутренний код страницы или тип
x:DataType, если вы используете шаблон данных. В этом случае метод — это знакомый методToString.NET, к которому осуществляется доступ через свойство элемента страницы, а затем через свойствоExposureэлемента. (Это показывает, как можно привязаться к методам и свойствам, которые глубоко вложены в цепочку соединений.)Привязка функции — это идеальный способ форматирования значений для отображения, так как вы можете передавать другие источники привязки в качестве аргументов метода, и выражение привязки будет отслеживать изменения этих значений, как и ожидалось, при одностороннем режиме. В этом примере аргумент языка и региональных параметров
является ссылкой на неизменное поле, реализованное в коде, но это может быть так же легко, как свойство, которое вызывает события. В этом случае любые изменения значения свойства приведут к тому, что выражение x:BindвызоветToStringс новым значением, а затем обновит пользовательский интерфейс с результатом.Сделайте то же самое для меток
TextBlock, которые отмечают другие ползунки эффектов.<Slider Header="Temperature" ... /> <TextBlock ... Text="{x:Bind item.Temperature.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Tint" ... /> <TextBlock ... Text="{x:Bind item.Tint.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Contrast" ... /> <TextBlock ... Text="{x:Bind item.Contrast.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Saturation" ... /> <TextBlock ... Text="{x:Bind item.Saturation.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Blur" ... /> <TextBlock ... Text="{x:Bind item.Blur.ToString('N', culture), Mode=OneWay}" />
Теперь, когда вы запускаете приложение, все работает, включая метки ползунка.
ползунки эффекта с активными метками 
Различия между привязкой и x:Bind
При создании привязок данных в XAML в приложениях UWP можно выбрать между Binding и x:Bind. Ниже приведены основные различия.
-
x:Bind: обеспечивает проверку во время компиляции, лучшую производительность и строгую типизацию. Лучше всего подходит для сценариев, когда структура данных известна во время компиляции. -
Binding: обеспечивает оценку среды выполнения и большую гибкость для динамических сценариев, таких как при определении структуры данных во время выполнения.
Сценарии, не поддерживаемые x:Bind
Хотя x:Bind это очень эффективно, он имеет ограничения в определенных сценариях:
-
Динамические структуры данных:
x:Bindнельзя использовать при определении структуры данных во время выполнения. -
Привязка между элементами: прямая привязка между двумя элементами пользовательского интерфейса не поддерживается
x:Bind. -
Наследование DataContext: в отличие от
Binding,x:Bindне наследуетDataContextот родительского элемента автоматически. -
Двусторонняя привязка:
x:Bindподдерживает двусторонняя привязка, что позволяет вносить изменения из пользовательского интерфейса обратно в исходное свойство. Для обновления пользовательского интерфейса при изменении исходного свойства (односторонняя или двусторонняя привязка) необходимо реализоватьINotifyPropertyChangedв объектах данных.
Дополнительные сведения и примеры см. в следующих ресурсах:
Заключение
Это руководство дало вам вкус привязки данных и показал вам некоторые доступные функциональные возможности. Одно слово осторожности перед тем, как мы заключим: не все привязывается, а иногда значения, к которым вы пытаетесь подключиться, несовместимы со свойствами, которые вы пытаетесь привязать. Существует много гибкости в привязке, но она не будет работать в каждой ситуации.
Один из примеров проблемы, не устраненной привязкой, заключается в том, что элемент управления не имеет подходящих свойств для привязки, как и функция масштабирования страницы сведений. Этот ползунок масштабирования должен взаимодействовать с ScrollViewer, отображающей изображение, но ScrollViewer можно обновить только с помощью метода ChangeView. В этом случае мы используем стандартные обработчики событий, чтобы синхронизировать ScrollViewer и ползунок масштабирования; подробности см. в методах ZoomSlider_ValueChanged и MainImageScroll_ViewChanged в DetailPage.
Тем не менее привязка — это эффективный и гибкий способ упростить код и сохранить логику пользовательского интерфейса отдельно от логики данных. Это значительно упрощает настройку любой стороны этого деления при снижении риска внедрения ошибок на другой стороне.
Одним из примеров разделения пользовательского интерфейса и данных является свойство ImageFileInfo.ImageTitle. Это свойство (и свойство ImageRating) немного отличается от свойства ItemSize, созданного в части 4, так как значение хранится в метаданных файла (предоставляемых через тип ImageProperties) вместо поля. Кроме того, ImageTitle возвращает значение ImageName (установлено как имя файла), если в метаданных файла нет заголовка.
public string ImageTitle
{
get => String.IsNullOrEmpty(ImageProperties.Title) ? ImageName : ImageProperties.Title;
set
{
if (ImageProperties.Title != value)
{
ImageProperties.Title = value;
var ignoreResult = ImageProperties.SavePropertiesAsync();
OnPropertyChanged();
}
}
}
Как видно, средство задания обновляет свойство ImageProperties.Title, а затем вызывает SavePropertiesAsync для записи нового значения в файл. (Это асинхронный метод, но мы не можем использовать ключевое слово await в свойстве — и вы бы не захотели, потому что методы получения и задания свойств должны завершаться немедленно. Зато вы вызовете метод и проигнорируете возвращаемый объект Task.)
Продвигаться дальше
Теперь, когда вы завершили эту лабораторную работу, у вас достаточно компетентных знаний, чтобы самостоятельно решить проблему.
Как вы могли заметить, если изменить уровень масштабирования на странице сведений, он сбрасывается автоматически при переходе назад, а затем снова выберите то же изображение. Можно ли выяснить, как сохранить и восстановить уровень масштабирования для каждого изображения по отдельности? Удачи!
У вас должны быть все необходимые сведения в этом руководстве, но если вам нужны дополнительные рекомендации, то документацию по привязке данных можно получить всего в один клик. Начните с этого: