Обзор привязки данных Windows
В этом разделе показано, как привязать элемент управления (или другой элемент пользовательского интерфейса) к одному элементу или привязать элемент управления элементами к коллекции элементов в приложении пакета SDK для приложений windows. Кроме того, мы покажем, как управлять отрисовкой элементов, реализовывать представление сведений на основе выделения и преобразовывать данные для отображения. Дополнительные сведения см. в подробной статье о привязке данных.
Необходимые компоненты
В этом разделе предполагается, что вы знаете, как создать базовое приложение пакета SDK для приложений Windows. Инструкции по созданию первого приложения пакета SDK для приложений Windows см. в статье "Создание первого проекта WinUI 3 (пакет SDK для приложений Windows).
Создание проекта
Создайте пустое приложение, упакованое (WinUI 3 в классическом приложении) C# . Назовите его "Краткое руководство".
Привязка к одному элементу
Каждая привязка состоит из целевого объекта привязки и источника привязки. Как правило, целевой объект — это свойство элемента управления или другого элемента пользовательского интерфейса, а источник — это свойство экземпляра класса (модель данных или модель представления). В этом примере показано, как привязать элемент управления к одному элементу. Целевой объект является свойством Text
объекта TextBlock
. Источник — это экземпляр простого класса Recording
, который представляет звукозапись. Давайте рассмотрим класс первым.
Добавьте новый класс в проект и присвойте этому классу Recording
имя.
namespace Quickstart
{
public class Recording
{
public string ArtistName { get; set; }
public string CompositionName { get; set; }
public DateTime ReleaseDateTime { get; set; }
public Recording()
{
ArtistName = "Wolfgang Amadeus Mozart";
CompositionName = "Andante in C for Piano";
ReleaseDateTime = new DateTime(1761, 1, 1);
}
public string OneLineSummary
{
get
{
return $"{CompositionName} by {ArtistName}, released: "
+ ReleaseDateTime.ToString("d");
}
}
}
public class RecordingViewModel
{
private Recording defaultRecording = new Recording();
public Recording DefaultRecording { get { return defaultRecording; } }
}
}
Затем предоставьте исходный класс привязки из класса, представляющего окно разметки. Для этого добавьте свойство типа RecordingViewModel
в MainWindow.xaml.cs.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
ViewModel = new RecordingViewModel();
}
public RecordingViewModel ViewModel{ get; set; }
}
}
Последний элемент заключается в привязке TextBlock
свойства к свойству ViewModel.DefaultRecording.OneLineSummary
.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Вот результат.
Привязка к коллекции элементов
Распространенный сценарий — привязка к коллекции бизнес-объектов. В C#универсальный класс ObservableCollection T> является хорошим выбором коллекции для привязки данных, так как он реализует интерфейсы INotifyPropertyChanged и INotifyCollectionChanged<. Эти интерфейсы предоставляют уведомление об изменении привязок при добавлении или удалении элементов или свойстве самого списка. Если вы хотите, чтобы связанные элементы управления обновлялись с изменениями свойств объектов в коллекции, бизнес-объект также должен реализовать INotifyPropertyChanged
. Дополнительные сведения см. в подробной статье о привязке данных.
Следующий пример привязывает ListView к коллекции Recording
объектов. Начнем с добавления коллекции в модель представления. Просто добавьте эти новые члены в RecordingViewModel
класс.
public class RecordingViewModel
{
...
private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
public ObservableCollection<Recording> Recordings{ get{ return recordings; } }
public RecordingViewModel()
{
recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
}
}
А затем привязать ListView к свойству ViewModel.Recordings
.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Window>
Мы еще не предоставили шаблон данных для Recording
класса, поэтому лучше всего использовать платформу пользовательского интерфейса для вызова ToString для каждого элемента в ListView. Реализация по умолчанию ToString
— возвращать имя типа.
Чтобы устранить эту проблему, можно переопределить ToString, чтобы вернуть значение OneLineSummary
или предоставить шаблон данных. Параметр шаблона данных является более распространенным и гибким решением. Вы указываете шаблон данных с помощью свойства ContentTemplate элемента управления содержимым или свойства ItemTemplate элемента управления элементами. Ниже приведены два способа разработки шаблона Recording
данных вместе с иллюстрацией результата.
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<TextBlock Text="{x:Bind OneLineSummary}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Дополнительные сведения о синтаксисе XAML см. в статье "Создание пользовательского интерфейса с помощью XAML". Дополнительные сведения о макете элемента управления см. в разделе "Определение макетов с помощью XAML".
Добавление представления сведений
Вы можете отобразить все сведения о объектах в элементах Recording
ListView. Но это занимает много места. Вместо этого можно отобразить достаточно данных в элементе, чтобы определить его, а затем, когда пользователь выбирает элемент, можно отобразить все сведения выбранного элемента в отдельном элементе пользовательского интерфейса, известном как представление сведений. Это расположение также называется представлением master/details или представлением списка и сведений.
Это можно сделать двумя способами. Представление сведений можно привязать к свойству SelectedItem объекта ListView. Или вы можете использовать CollectionViewSource, в этом случае вы привязываете как представление сведений, так ListView
и представление сведений к CollectionViewSource
этому элементу (это делает для вас выбранный в данный момент элемент). Оба способа описаны ниже. Они дают аналогичные результаты, показанные на картинке.
Примечание.
До сих пор в этом разделе мы использовали только расширение разметки {x:Bind}, но оба метода, которые мы рассмотрим ниже, требуют более гибкого (но менее производительного) расширения разметки {Binding} .
Во-первых , вот метод SelectedItem . Для приложения C# необходимо внести только изменения в разметку.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
Margin="0,24,0,0">
<TextBlock Text="{Binding ArtistName}"/>
<TextBlock Text="{Binding CompositionName}"/>
<TextBlock Text="{Binding ReleaseDateTime}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
Для метода CollectionViewSource сначала добавьте CollectionViewSource
ресурс в виде окна.
<Window.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Window.Resources>
А затем настройте привязки в ListView (которые больше не должны быть названы) и в представлении сведений для использования CollectionViewSource. Обратите внимание, что путем привязки представления сведений непосредственно к CollectionViewSource
коллекции подразумевается, что вы хотите привязать к текущему элементу в привязках, где путь не найден в самой коллекции. Нет необходимости указывать CurrentItem
свойство в качестве пути для привязки, хотя это можно сделать, если есть какая-либо неоднозначность).
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
И вот одинаковый результат в каждом случае.
Форматирование или преобразование значений данных для отображения
С описанной выше визуализацией связана одна проблема. Это ReleaseDateTime
свойство не просто дата, это DateTime. Таким образом, он отображается с большей точностью, чем нам нужно. Одним из решений является добавление строкового Recording
свойства в класс, возвращающий эквивалент ReleaseDateTime.ToString("d")
. Именование этого свойства ReleaseDate
означает, что он возвращает дату, а не дату и время. Именование будет ReleaseDateAsString
также указывать на то, что он возвращает строку.
Более гибкое решение — использовать что-то известное как преобразователь значений. Ниже приведен пример создания собственного преобразователя значений. Добавьте приведенный ниже код в файл исходного кода Recording.cs .
public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
// This converts the value object to the string to display.
// This will work with most simple types.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// Retrieve the format string and use it to format the value.
string formatString = parameter as string;
if (!string.IsNullOrEmpty(formatString))
{
return string.Format(formatString, value);
}
// If the format string is null or empty, simply
// call ToString() on the value.
return value.ToString();
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Теперь можно добавить экземпляр StringFormatter
в качестве ресурса страницы и использовать его в привязке TextBlock
отображаемого ReleaseDateTime
свойства.
<Window.Resources>
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Window.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Как видно выше, чтобы повысить гибкость форматирования, мы используем разметку для передачи строки формата в преобразователь с помощью параметра преобразователя. В примере кода, приведенном в этом разделе, преобразователь значений C# использует этот параметр.
Вот результат.
См. также
Windows developer
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по