При прив'язці до об'єкта, яка не є елементом, слід відмовитися від властивості Binding.ElementName і застосовувати замість нього одне з наступних властивостей:
Вказує на вихідний об'єкт, який використовує об'єкт RelativeSource, який дозволяє базувати посилання на поточному елементі. Це спеціалізований інструмент, який зручний при написанні шаблонів елементів управління і шаблонів даних.
Якщо джерело не вказано за допомогою властивості Source або RelativeSource, то середовище WPF здійснює пошук в дереві елементів, починаючи з поточного елемента. Вона перевіряє властивість DataContext кожного елемента і використовує перший з них, що не дорівнює null. Властивість DataContext виключно корисно, коли потрібно прив'язати кілька властивостей одного об'єкта до різних елементів, тому що можна встановити властивість DataContext високорівневого об'єкта контейнера, замість його установки безпосередньо на цільової елемент.
Нижче ці варіанти описані більш детально.
властивість Source
Властивість Source досить прямолінійно. Єдиний момент, який слід враховувати - об'єкт даних повинен бути зроблений зручним для прив'язки. Як буде показано, для отримання об'єкта даних існує кілька підходів: витягти його з ресурсу, генерувати програмно або отримати від постачальника даних.
Найпростіший варіант - встановити Source в певний готовий і доступний статичний об'єкт. Наприклад, можна створити статичний об'єкт в коді і використовувати його. Або ж можна застосувати інгредієнт з бібліотеки класів .NET, як показано нижче:
Цей вислів прив'язки отримує об'єкт FontFamily, який надано властивістю SystemFonts.IconFontFamily. (Зверніть увагу, що для установки властивості Binding.Source знадобиться допомога розширення розмітки Static.) Потім властивість Binding.Path встановлюється в властивість FontFamily.Source, яке видає ім'я сімейства шрифтів. Результатом буде єдиний рядок тексту. У Windows Vista або Windows 7 ім'я шрифту виглядає як Segoe UI.
Інший варіант полягає в прив'язці до об'єкта, який раніше створювався у вигляді ресурсу. Наприклад, наступна розмітка створює об'єкт FontFamily, який вказує на шрифт Calibri:
властивість RelativeSource
Властивість RelativeSource дозволяє встановити його в вихідний об'єкт на основі його ставлення до цільового об'єкту. Наприклад, властивістю RelativeSource можна скористатися для прив'язки елемента до самого себе або для прив'язки до батьківського елементу, який знаходиться в невідомому кількості рівнів вище в дереві елементів.
Для установки властивості Binding.RelativeSource застосовується об'єкт RelativeSource. Це дещо ускладнює синтаксис, оскільки потрібно створити об'єкт Binding і всередині нього - вкладений об'єкт RelativeSource. Один варіант полягає у використанні синтаксису установки властивості замість розширення розмітки Binding.
Наприклад, в наступному коді створюється об'єкт Binding для властивості TextBlock.Text. Об'єкт Binding використовує RelativeSource, яке шукає батьківське вікно і відображає заголовок вікна:
Для об'єкта RelativeSource обраний режим FindAncestor, який змушує його здійснювати пошук вгору по дереву елементів до тих пір, поки не буде знайдений тип елемента, певний властивістю AncestorType.
Найбільш загальний спосіб запису цієї прив'язки полягає в комбінуванні її в один рядок, використовуючи розширення розмітки Binding і RelativeSource, як показано нижче:
Режим FindAncestor - один з чотирьох можливих варіантів при створенні об'єкта RelativeSource. Всі варіанти коротко описані нижче:
Вираз прив'язується до іншого властивості того ж елемента
Вираз прив'язується до батьківського елементу. WPF буде проводити пошук вгору по дереву елементів, поки не знайде потрібний батьківський елемент. Щоб вказати батька, необхідно також встановити властивість AncestorType для індикації типу батьківського елемента, який повинен бути знайдений. Додатково за допомогою властивості AncestorLevel можна пропустити певну кількість збігів зазначеного елемента. Наприклад, якщо потрібно прив'язка до третього елементу типу ListBoxItem при сходженні вгору по дереву, то слід встановити AncestorType = і AncestorLevel = 3, тим самим пропускаючи перші два ListBoxItem. За замовчуванням AncestorLevel дорівнює 1, і пошук припиняється на першому знайденому елементі.
Вираз здійснює прив'язку до попереднього елемента даних в списку, прив'язаному до даних. Це можна використовувати в елементі списку
Вираз здійснює прив'язку до елементу, до якого застосовано шаблон. Цей режим працює, тільки якщо прив'язка знаходиться всередині шаблону елемента управління або шаблону даних
На перший погляд властивість RelativeSource може бути зайвим ускладненням розмітки. Зрештою, чому б просто не прив'язатися безпосередньо до необхідного джерела, використовуючи властивість Source або ElementName? Однак, це не завжди можливо, і зазвичай тому, що об'єкт-джерело і цільової об'єкт знаходяться в різних частинах розмітки. Так виходить при створенні шаблонів елементів управління і шаблонів даних. Наприклад, при побудові шаблону даних, який змінює спосіб представлення елементів в списку, може знадобитися доступ до об'єкта ListBox верхнього рівня, щоб прочитати якийсь його властивість.
властивість DataContext
У деяких випадках є безліч елементів, прив'язаних до одного об'єкту. Наприклад, розглянемо наступну групу елементів TextBlock, кожен з яких використовує вихідне вираз прив'язки для видобування різних деталей про шрифт, значків за замовчуванням, включаючи проміжки між рядками, стиль і вага першої гарнітури (те й інше - просто Regular). Можете скористатися властивістю Source для кожного з них, але це призводить до досить довгою розмітці:
У такій ситуації було б ясніше і зручніше визначити джерело прив'язки один раз за допомогою властивості FrameworkElement.DataContext. В даному прикладі має сенс встановити властивість DataContext елемента StackPanel, що містить в собі всі елементи TextBlock. (Можна було б також встановити властивість DataContext на ще більш високому рівні, наприклад, на рівні всього вікна, але краще визначити його наскільки можливо вже, щоб ясніше висловити наміри.)
Встановити властивість DataContext елемента можна таким же чином, як встановлюється властивість Binding.Source. Іншими словами, можна вбудувати об'єкт, витягти його з статичного властивості або отримати з ресурсу, як показано нижче:
Після цього виразу прив'язки спрощуються за рахунок виключення деякої інформації про джерело:
Коли інформація про джерело відсутнє в вираженні прив'язки, WPF перевіряє властивість DataContext елемента. Якщо воно дорівнює null, WPF шукає в дереві елементів перший контекст даних, відмінний від null. (Спочатку властивості DataContext всіх елементів рівні null.) Якщо відповідний контекст даних виявлено, то він використовується для прив'язки. Якщо ж ні, то вираз прив'язки залишають поза передачею ніякого значення цільовим властивості.