Основы привязки данных в WPF. Привязка данных к к пользовательскому интерфейсу. Использование иерархических шаблонов данных

  • Программирование
  • Одним из ключевых моментов в разработке xaml -ориентированных приложений является использование привязок (Bindings ). Привязка - это медиатор (посредник), с помощью которого синхронизируются значения свойств между связанными объектами.

    Стоит отметить не очевидный, но важный нюанс: хотя привязка так или иначе ссылается на взаимодействующие объекты, она не удерживает их от сборки мусора!

    Наследование от класса Binding разрешено, но в целях безопасности кода переопределение метода ProvideValue , который связан с основной логикой работы, не допускается. Это так или иначе провоцирует разработчиков на применение паттерна Converter , который тесно переплетается с темой привязок.

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


    Объявлять привязки в xaml допустимо двумя образами:



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


    В простейшем случае нужно унаследоваться от класса MarkupExtension и реализовать метод ProvideValue , в котором по ключу получить нужное значение.

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

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

    Более того, на xaml -платформах Windows Phone , Windows Store и Xamarin.Forms нет возможности создавать пользовательские расширения разметки, что наталкивает на идею использования привязок в качестве расширений разметки

    Не будем ходить вокруг да около, вот то, что нам нужно:

    Public abstract class BindingExtension: Binding, IValueConverter { protected BindingExtension() { Source = Converter = this; } protected BindingExtension(object source) // set Source to null for using DataContext { Source = source; Converter = this; } protected BindingExtension(RelativeSource relativeSource) { RelativeSource = relativeSource; Converter = this; } public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture); public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
    Примечательно, что привязка является конвертером для самой себя. В результате мы получаем поведение очень похожее, как при наследовании от класса MarkupExtension , но, кроме того, остаётся возможность использовать стандартные механизмы контроля сборки мусора!

    Теперь логика для локализации выглядит проще некуда:

    Public partial class Localizing: Base.BindingExtension { public static readonly Manager ActiveManager = new Manager(); public Localizing() { Source = ActiveManager; Path = new PropertyPath("Source"); } public Localizing(string key) { Key = key; Source = ActiveManager; Path = new PropertyPath("Source"); } public string Key { get; set; } public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var key = Key; var resourceManager = value as ResourceManager; var localizedValue = resourceManager == null || string.IsNullOrEmpty(key) ? ":" + key + ":" : (resourceManager.GetString(key) ?? ":" + key + ":"); return localizedValue; } }
    public partial class Localizing { public class Manager: INotifyPropertyChanged { private ResourceManager _source; public ResourceManager Source { get { return _source; } set { _source = value; PropertyChanged(this, new PropertyChangedEventArgs("Source")); } } public string Get(string key, string stringFormat = null) { if (_source == null || string.IsNullOrWhiteSpace(key)) return key; var localizedValue = _source.GetString(key) ?? ":" + key + ":"; return string.IsNullOrEmpty(stringFormat) ? localizedValue: string.Format(stringFormat, localizedValue); } public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { }; } }
    Легко добавить возможность для смены регистра букв:

    Public partial class Localizing: Base.BindingExtension { public enum Cases { Default, Lower, Upper } public static readonly Manager ActiveManager = new Manager(); public Localizing() { Source = ActiveManager; Path = new PropertyPath("Source"); } public Localizing(string key) { Key = key; Source = ActiveManager; Path = new PropertyPath("Source"); } public string Key { get; set; } public Cases Case { get; set; } public override string ToString() { return Convert(ActiveManager.Source, null, Key, Thread.CurrentThread.CurrentCulture) as string ?? string.Empty; } public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var key = Key; var resourceManager = value as ResourceManager; var localizedValue = resourceManager == null || string.IsNullOrEmpty(key) ? ":" + key + ":" : (resourceManager.GetString(key) ?? ":" + key + ":"); switch (Case) { case Cases.Lower: return localizedValue.ToLower(); case Cases.Upper: return localizedValue.ToUpper(); default: return localizedValue; } } }
    В xaml запись выглядит удобно и красиво, но есть некоторые ограничения парсеров разметки на различных платформах:


    Чтобы избавиться на WPF от обязательного префикса m: нужно поместить расширение разметки в отдельную сборку и в Properties/AssemblyInfo.cs указать следующие директивы:


    Для регулирования имени префикса на Windows Phone или Store :


    Использование расширений привязки (Binding Extensions ) на WPF не исключает обычных расширений разметки, но в некоторых случаях является даже более безопасным и простым вариантом. Также всё это не ограничивается одной лишь локализацией, а пригодно для множества других целей...

    Продемонстрированный подход интенсивно используется в библиотеке

    Последнее обновление: 7.02.2016

    В WPF привязка (binding) является мощным инструментом программирования, без которого не обходится ни одно серьезное приложение.

    Привязка подразумевает взаимодействие двух объектов: источника и приемника. Объект-приемник создает привязку к определенному свойству объекта-источника. В случае модификации объекта-источника, объект-приемник также будет модифицирован. Например, простейшая форма с использованием привязки:

    Для определения привязки используется выражение типа:

    {Binding ElementName=Имя_объекта-источника, Path=Свойство_объекта-источника}

    То есть в данном случае у нас элемент TextBox является источником, а TextBlock - приемником привязки. Свойство Text элемента TextBlock привязывается к свойству Text элемента TextBox. В итоге при осуществлении ввода в текстовое поле синхронно будут происходить изменения в текстовом блоке.

    Работа с привязкой в C#

    Ключевым объектом при создании привязки является объект System.Windows.Data.Binding . Используя этот объект мы можем получить уже имеющуюся привязку для элемента:

    Binding binding = BindingOperations.GetBinding(myTextBlock, TextBlock.TextProperty);

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

    Также можно полностью установить привязку в коде C#:

    Public MainWindow() { InitializeComponent(); Binding binding = new Binding(); binding.ElementName = "myTextBox"; // элемент-источник binding.Path = new PropertyPath("Text"); // свойство элемента-источника myTextBlock.SetBinding(TextBlock.TextProperty, binding); // установка привязки для элемента-приемника }

    Если в дальнейшем нам станет не нужна привязка, то мы можем воспользоваться классом BindingOperations и его методами ClearBinding() (удаляет одну привязку) и ClearAllBindings() (удаляет все привязки для данного элемента)

    BindingOperations.ClearBinding(myTextBlock, TextBlock.TextProperty);

    BindingOperations.ClearAllBindings(myTextBlock);

    Некоторые свойства класса Binding :

      ElementName : имя элемента, к которому создается привязка

      IsAsync : если установлено в True, то использует асинхронный режим получения данных из объекта. По умолчанию равно False

      Mode : режим привязки

      TargetNullValue : устанавливает значение по умолчанию, если привязанное свойство источника привязки имеет значение null

      RelativeSource : создает привязку относительно текущего объекта

      Source : указывает на объект-источник, если он не является элементом управления.

      XPath : используется вместо свойства path для указания пути к xml-данным

    Режимы привязки

    Свойство Mode объекта Binding, которое представляет режим привязки, может принимать следующие значения:

      OneWay : свойство объекта-приемника изменяется после модификации свойства объекта-источника.

      OneTime : свойство объекта-приемника устанавливается по свойству объекта-источника только один раз. В дальнейшем изменения в источнике никак не влияют на объект-приемник.

      TwoWay : оба объекта - применки и источник могут изменять привязанные свойства друг друга.

      OneWayToSource: объект-приемник, в котором объявлена привязка, меняет объект-источник.

      Default : по умолчанию (если меняется свойство TextBox.Text , то имеет значение TwoWay, в остальных случаях OneWay).

    Применение режима привязки:

    Обновление привязки. UpdateSourceTrigger

    Односторонняя привязка от источника к приемнику практически мгновенно изменяет свойство приемника. Но если мы используем двустороннюю привязку в случае с текстовыми полями (как в примере выше), то при изменении приемника свойство источника не изменяется мгновенно. Так, в примере выше, чтобы текстовое поле-источник изменилось, нам надо перевести фокус с текстового поля-приемника. И в данном случае в дело вступает свойство UpdateSourceTrigger класса Binding, которое задает, как будет присходить обновление. Это свойство в качестве принимает одно из значений перечисления UpdateSourceTrigger :

      PropertyChanged: источник привязки обновляется сразу после обновления свойства в приемнике

      LostFocus: источник привязки обновляется только после потери фокуса приемником

      Explicit: источник не обновляется до тех пор, пока не будет вызван метод BindingExpression.UpdateSource()

      Default: значение по умолчанию. Для большинства свойств это значение PropertyChanged . А для свойства Text элемента TextBox это значение LostFocus

    В данном случае речь идет об обновлении источника привязки после изменения приемника в режимах OneWayToSource или TwoWay . То есть чтобы у нас оба текстовых поля, которые связаны режимом TwoWay, моментально обновлялись после изменения одного из них, надо использовать значение UpdateSourceTrigger.PropertyChanged:

    Свойство Source

    Свойство Source позволяет установить привязку даже к тем объектам, которые не являются элементами управления WPF. Например, определим класс Phone:

    Class Phone { public string Title { get; set; } public string Company { get; set; } public int Price { get; set; } }

    Теперь создадим объект этого класса и определим к нему привязку:

    Свойство TargetNullValue

    На случай, если свойство в источнике привязки вдруг имеет значение null, то есть оно не установлено, мы можем задать некоторое значение по умолчанию. Например:

    В данном случае у ресурса nexusPhone не установлено свойство Title, поэтому текстовый блок будет выводить значение по умолчанию, указанное в параметре TargetNullValue.

    Свойство RelativeSource

    Свойство RelativeSource позволяет установить привязку относительно элемента-источника, который связан какими-нибудь отношениями с элементом-приемником. Например, элемент-источник может быть одним из внешних контейнеров для элемента-приемника. Либо источником и приемником может быть один и тот же элемент.

    Для установки этого свойства используется одноименный объект RelativeSource . У этого объекта есть свойство Mode , которое задает способ привязки. Оно принимает одно из значений перечисления RelativeSourceMode :

      Self: привязка осуществляется к свойству этого же элемента. То есть элемент-источник привязки в то же время является и приемником привязки.

      FindAncestor: привязка осуществляется к свойству элемента-контейнера.

    Например, совместим источник и приемник привязке в самом элементе:

    Здесь текст и фоновый цвет текстового поля связаны двусторонней привязкой. В итоге мы можем увидеть в поле числовое значение цвета, поменять его, и вместе с ним изменится и фон поля.

    Привязка к свойствам контейнера:

    При использовании режима FindAncestor, то есть привязке к контейнеру, необходимо еще указывать параметр AncestorType и передавать ему тип контейнера в виде выражения AncestorType={x:Type Тип_элемента-контейнера} . При этом в качестве контейнера мы могли бы выбрать любой контейнер в дереве элементов, в частности, в данном случае кроме Grid таким контейнером также является элемент Window.

    Свойство DataContext

    У объекта FrameworkElement , от которого наследуются элементы управления, есть интересное свойство DataContext . Оно позволяет задавать для элемента и вложенных в него элементов некоторый контекст данных. Тогда вложенные элементы могут использовать объект Binding для привязки к конкретным свойствам этого контекста. Например, используем ранее определенный класс Phone и создадим контекст данных из объекта этого класса:

    Таким образом мы задаем свойству DataContext некоторый динамический или статический ресурс. Затем осуществляем привязку к этому ресурсу.

    Аннотация: В данном разделе рассматриваются основные понятия привязки данных в WPF. На ряде примеров демонстрируются базовые аспекты привязки интерфейсных элементов к визуальным и невизуальным объектам WPF. Более серьезные вопросы, такие как привязка интерфейсных элементов WPF к пользовательским объектам и коллекциям типизированных данных, объектам инфраструктуры ADO.NET и шаблонам, будут рассмотрены позднее.

    Часть I

    Общие положения

    Все необходимые для выполнения данной работы программы можно найти в прилагаемом каталоге .

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

    В привязке данных всегда участвуют две стороны: источник и приемник (целевой элемент) информации. Привязка данных может обеспечивать однонаправленный или двунаправленный обмен данными связанных свойств объектов. Чаще всего применяется однонаправленная привязка, целью которой является извлечение информации из источника и отображение ее на приемнике. Но в некоторых случаях различия между источником и приемником стираются, а иногда даже их роли меняются местами - приемник начинает поставлять данные источнику.

    Синтаксис привязки данных, как и в случае с ресурсами, также имеет два варианта: расширения разметки и элементов свойств , но отличается деталями. Ключевым элементом привязки для любого варианта является определение объекта Binding из пространства имен System.Windows.Data . Этот элемент всегда устанавливается на стороне приемника привязки, кроме режима Mode=OneWayToSource . Приемник должен быть производным от класса DependencyObject и привязываемое свойство (целевое свойство) должно быть свойством зависимости . В свойства зависимостей встроена способность посылать или принимать уведемления об изменениях.

    К источнику привязки предъявляется гораздо меньше требований. Связываемое свойство источника не обязано быть зависимым свойством. Главное, чтобы источник имел оповещающее событие, указывающее на изменение связываемого свойства. Источником привязки может быть любое открытое свойство, в том числе свойства других элементов управления, объекты среды CLR, элементы XAML, наборы данных ADO.NET, фрагменты XML и т.д. Для правильного применения привязки к сложным объектам данных технология WPF предоставляет два специализированных класса - XmlDataProvider и ObjectDataProvider .

    Свойства зависимостей еще называют присоединенными . В версии XAML , предназначенной для WPF , присоединенные свойства работают только в том случае, если и тип, в котором свойство определено, и тип, к которому оно присоединяется, оба наследуют классу DependencyObject . С помощью свойств зависимостей язык XAML имеет возможность расширять типы за счет свойств, предоставляемых другими типами. При использовании в разметке по синтаксису элементов свойств присоединенному свойству всегда предшествует имя предоставляющего его типа, даже если такое свойство употребляется в качестве атрибута.

    Направления привязки

    Тип привязки элемента Binding определяется его свойством Mode, которое может принимать одно из значений перечисления BindingMode из пространства имен System.Windows.Data :

    • Default - установлен по умолчанию и зависит от типа привязываемого свойства на стороне приемника (целевого свойства). Действует как режим двухсторонней привязки TwoWay для свойств, доступных для редактирования в пользовательском интерфейсе, таких как TextBox.Text или CheckBox.Checked, либо - как односторонняя привязка OneWay для иных свойств. Чтобы не полагаться на настройки по умолчанию, следует взять себе за правило - всегда явно устанавливать параметр направления привязки.
    • OneTime - односторонняя начальная привязка, когда значение целевого свойства устанавливается по значению источника только один раз: при инициализации, программной замены привязанного объекта-источника на новый, при изменении свойства DataContext или в результате программного вызова метода BindingExpression.UpdateTarget (). Иные поступающие уведомления об изменениях на стороне источника приемником учитываться не будут
    • OneWay - односторонняя привязка, когда целевое свойство обновляется при изменении свойства источника. Каждый раз при изменении на стороне источника поток данных направлен от источника к целевому объекту.
    • OneWayToSource - организует однонаправленную привязку, как и OneWay, только выражение привязки помещается в источник. Этот трюк может понадобиться в том случае, когда привязываемое свойство-приемник не является свойством зависимости, а свойство источника все-таки наследует классу DependencyObject .
    • TwoWay - двухсторонняя привязка, когда целевое свойство обновляется при изменении свойства источника и свойство-источник обновляется при изменении целевого свойства. Иными словами, режим привязки TwoWay отправляет данные от источника к целевому объекту, а в случае изменения значения свойства целевого объекта данные отправляются обратно от целевого объекта к источнику

    Упражнение 1. Привязка элемента к элементу

    В данном упражнении на ряде примеров рассмотрим вопросы создания канала связи между свойствами зависимости визуальных элементов WPF пользовательского интерфейса.

    >

    Вот вы и создали полноценные страницы для вашего приложения. Теперь вы, наверно, захотите заполнить их различными данными.

    В этой части вы узнаете:

    • Как привязать данные к пользовательскому интерфейсу.
    • Как Visual Studio может помочь вам создать привязки к данным.
    • Как отображать данные в списке.
    • Как работать с более сложными сценариями привязки.

    Привязка данных к к пользовательскому интерфейсу

    Приложение Fuel Tracker имеет три страницы с данными. Данные хранятся в основном в трёх классах. На следующем изображении показаны страницы и связанные с ними классы.

    Для отображения данных обычно используется привязка данных (data binding). Привязка данных предоставляет возможность подключения пользовательского интерфейса к источнику данных. Когда привязки созданы и источник данных изменяется, элементы пользовательского интерфейса, которые связаны с источником данных отображают изменения автоматически. Аналогично, изменения, внесённые пользователем в элемент пользовательского интерфейса отражаются в источнике данных. Например, если пользователь изменит значение в TextBox, соответствующий источник данных автоматически обновится, чтобы отразить эти изменения.

    Следующий фрагмент XAML-кода иллюстрирует синтаксис, который используется для привязки свойства Text элемента управления TextBox к свойству Name объекта-источника.

    1. < TextBox x:Name ="NameTextBox" Text ="{Binding Name, Mode=TwoWay}" />

    На следующем изображении показан пример такой привязки.

    Каждая привязка имеет свойство Mode (режим), которое определяет, как и когда обновляются данные. OneWay (односторонняя) привязка означает, что целевой (target) элемент пользовательского интерфейса обновляется, если источник изменяется. TwoWay (двухсторонняя) привязка означает, что как цель, так и источник обновляются, если кто-либо из них изменяется. Если вы используете OneWay или TwoWay привязки, то для того, чтобы привязка была уведомлена об изменениях объекта-источника, необходимо реализовать интерфейс INotifyPropertyChanged. Этот интерфейс будет более подробно обсуждаться в следующей части «Создание классов данных».

    Вы указываете объект-источник, устанавливая свойство DataContext (контекст данных). Если вы используете элемент управления ListBox, необходимо указать объект-источник, установив свойство ItemsSource. В следующем примере показано, как задать свойству DataContext панели CarHeader объект-источник, извлекаемый из статического свойства.

    1. CarHeader.DataContext = CarDataStore.Car;
    * This source code was highlighted with Source Code Highlighter .

    Свойство DataContext позволяет установить стандартную привязку для всего элемента пользовательского интерфейса, включая все его дочерние элементы. В некоторых случаях вам будет удобней установить свойство DataContext для всей страницы, а в некоторых будет удобней установить его отдельно для каждого элемента на странице. Установка DataContext на каждом уровне XAML перекрывает любые установки на более высоком уровне. Кроме того, вы можете фактически переопределить любую установку DataContext для отдельных привязок, установив для них свойство Source (источник).

    Например, в приложение Fuel Tracker каждая страница устанавливает DataContext в различное значение. Однако, на странице FillupPage DataContext уровня страницы переопределяется для панели, которая отображает название автомобиля и его фотографию. На следующем изображении показаны настройки контекста данных для приложения Fuel Tracker.

    Использование data binding builder

    Visual Studio включает в себя data binding builder (создатель привязок данных), чтобы помочь вам создать привязки данных в XAML. Хотя data binding builder может обеспечить повышение производительности, он не поддерживает все возможные сценарии. Например, он не поддерживает привязку к индексированным элементам и он не распознаёт привязки, созданные в коде. Таким образом, в некоторых случаях вам потребуется указать привязки данных вручную.

    Отображение данных в списке

    Отображение коллекции элементов в списке - одна из основных задач на телефоне. Для того, чтобы отобразить коллекцию элементов в списке с помощью привязки данных вам необходимо сделать следующее:
    1. Добавить ListBox в ваше приложение.
    2. Указать источник данных для ListBox путем привязки коллекции к свойству ItemsSource.
    3. Чтобы настроить внешний вид каждого элемента в ListBox, добавьте шаблон данных для ListBox.
    4. В шаблоне данных привяжите элементы ListBox к свойствам коллекции элементов.
    На следующем изображении показаны привязки для ListBox на странице сводной информации приложения Fuel Tracker.

    Следующий XAML-код показывает, как были указаны привязки для ListBox.

    1. < ListBox ItemContainerStyle ="{StaticResource ListBoxStyle}"
    2. ItemsSource ="{Binding FillupHistory}"
    3. Height ="380" HorizontalAlignment ="Left" Margin ="5,25,0,0"
    4. VerticalAlignment ="Top" Width ="444" >
    5. < ListBox.ItemTemplate >
    6. < DataTemplate >
    7. < StackPanel Orientation ="Horizontal" >
    8. < TextBlock Style
    9. Text ="{Binding Date, Converter={StaticResource StringFormatter}, ConverterParameter=\{0:d\} }"
    10. Width ="105" TextWrapping ="Wrap" />
    11. < TextBlock Style ="{StaticResource SummaryStyle}"
    12. Text ="{Binding FuelQuantity}" TextWrapping ="Wrap" />
    13. < TextBlock Style ="{StaticResource SummaryStyle}"
    14. Text ="{Binding DistanceDriven}" TextWrapping ="Wrap" />
    15. < TextBlock Style ="{StaticResource SummaryStyle}"
    16. Text ="{Binding PricePerFuelUnit, Converter={StaticResource StringFormatter}, ConverterParameter=\{0:c\}, ConverterCulture=en-US}" />
    17. < TextBlock Style ="{StaticResource SummaryStyle}"
    18. Text ="{Binding FuelEfficiency, Converter={StaticResource StringFormatter}, ConverterParameter=\{0:F\}}" TextWrapping ="Wrap" />
    * This source code was highlighted with Source Code Highlighter .

    В предыдущем XAML-коде, свойство ListBox.ItemsSource привязано к свойству Car.FillupHistory так, что каждый объект Fillup в коллекции истории появится в качестве отдельного пункта в ListBox. Элемент DataTemplate определяет внешний вид каждого пункта и содержит несколько элементов TextBlock, каждый из которых привязан к свойству класса Fillup .

    Этот XAML будет работать только тогда, когда объект Car впервые ассоциирован со страницей, как показано в следующем коде из SummaryPage.xaml.cs.

    1. this .DataContext = CarDataStore.Car;
    * This source code was highlighted with Source Code Highlighter .

    Совет по улучшению производительности:
    Если прокрутка в вашем ListBox не кажется плавной и отзывчивый, воспользуйтесь следующими советами:
    • Упростите элементы в ListBox .
    • Загружайте изображения в фоновом режиме.
    • Используйте виртуализацию данных.
    • Обратите внимание на использование DeferredLoadListBox или LazyListBox .
    • Не используйте вложенные списки.

    Сложные пути привязки

    В дополнение к гибкости настройки свойства DataContext на любом уровне (что позволяет переопределить настройки на более высоком уровне), можно также указать сложные пути привязки для того, чтобы «пробуриться» в свойства ссылки, такой как Car.FillupHistory . Например, следующий XAML-код из SummaryPage.xaml демонстрирует привязку к свойству Fillup.FuelEfficiency первого пункта в коллекции истории заправок.
    1. < TextBlock Text ="{Binding FillupHistory.FuelEfficiency, Converter={StaticResource StringFormatter}, ConverterParameter=\{0:F\}}" />
    * This source code was highlighted with Source Code Highlighter .

    На следующем изображении показаны привязки в SummaryPage.xaml и показывается, как сложные привязки и шаблоны данных позволяют вам привязывать элементы управления к различным свойствам различных объектов, даже если они все относятся к тому же DataContext.

    Зеленые прямоугольники на левом экране Pivot показывают элементы управления, которые привязаны с использованием сложных путей. Эти пути начинаются с первого элемента (индекс 0) в коллекции Car.FillupHistory и заканчиваются различными свойствами класса Fillup . Например, поле Current MPG использует путь привязки FillupHistory.FuelEfficiency . Если вы включите в этот путь настройку DataContext страницы, весь путь привязки будет выглядеть следующим образом: CarDataStore.Car.FillupHistory.FuelEfficiency .

    Теги:

    • windows phone 7
    • создание приложения
    • от начала до конца
    Добавить метки