TOC

This article is currently in the process of being translated into Russian (~94% done).

Связывание данных:

Отладка связывания данных

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

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10" Name="pnlMain">
		<TextBlock Text="{Binding NonExistingProperty, ElementName=pnlMain}" />
	</Grid>
</Window>

Окно вывода

Прежде всего вам необходимо посмотреть на Окно вывода (Output window) Visual Studio. Оно должно быть расположено в нижней части главного окна Visual Studio (вы можете сделать его активным используя сочетание клавиш [Ctrl+Alt+O]. Здесь отображаются выходные данные, полученные от отладчика, но при запуске вышеупомянутого примера, среди этих данных вам нужно обнаружить строку, похожую на эту:

System.Windows.Data Error: 40 : BindingExpression path error: 'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'. BindingExpression:Path=NonExistingProperty; DataItem='Grid' (Name='pnlMain'); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

Это громоздкое сообщение может показаться избыточным, в основном из-за того что в нём отсутствуют разрывы строк, но самая важная часть содержится вот здесь:

'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.

Это говорит о том, что вы попытались применить свойство с именем "NonExistingProperty" для объекта типа Grid с именем pnlMain. Теперь сообщение стало достаточно понятным, и оно должно помочь вам исправить имя свойства либо привязать существующий объект, если возникла проблема такого рода.

Изменение уровня диагностической информации (trace level)

Ошибку в вышеприведённом примере легко исправить, так как для WPF было понятно, что мы пытались сдеалать и почему это не сработало. Но давайте рассмотрим следующий пример:

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10">
		<TextBlock Text="{Binding Title}" />
	</Grid>
</Window>

Здесь мы пытаемся сделать привязку к свойству "Title", но какого объекта? Как обсуждалось в главе, посвящённой контексту данных, WPF использует свойство DataContext элемента TextBlock, которое наследуется вниз по иерархии элементов управления, но в этом примере мы забыли задать контекст данных. Это фактически означает, что мы пытаемся получить свойство объекта NULL. WPF предположит, что эта привязка абсолютно корректна, но объект просто пока не был инициализирован, и не будет сообщать об этом. Если вы запустите этот пример и посмотрите на окно Output, вы не увидите ошибок привязки данных.

Однако в случаях, если это поведение программы вам не подходит, существует возможность заставить WPF сообщать вам о возникающих проблемах привязки данных. Этого можно добиться установкой TraceLevel объекта PresentationTraceSources, которые находятся в пространстве имён System.Diagnostics:

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10">
		<TextBlock Text="{Binding Title, diag:PresentationTraceSources.TraceLevel=High}" />
	</Grid>
</Window>

Обратите внимание, мы добавили ссылку на пространство имён System.Diagnostics в заголовке окна и затем задали свойство для привязки данных. В результате WPF будет выводить информацию об этой привязке в окне Output:

System.Windows.Data Warning: 55 : Created BindingExpression (hash=2902278) for Binding (hash=52760599)
System.Windows.Data Warning: 57 :   Path: 'Title'
System.Windows.Data Warning: 59 : BindingExpression (hash=2902278): Default mode resolved to OneWay
System.Windows.Data Warning: 60 : BindingExpression (hash=2902278): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 61 : BindingExpression (hash=2902278): Attach to System.Windows.Controls.TextBlock.Text (hash=18876224)
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 64 : BindingExpression (hash=2902278): Resolve source deferred
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source  (last chance)
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 77 : BindingExpression (hash=2902278): Activate with root item <null>
System.Windows.Data Warning: 105 : BindingExpression (hash=2902278):   Item at level 0 is null - no accessor
System.Windows.Data Warning: 79 : BindingExpression (hash=2902278): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 87 : BindingExpression (hash=2902278): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 88 : BindingExpression (hash=2902278): TransferValue - using final value ''

Изучив данный список событий, мы сможем понять весь процесс, который происходит в WPF при поиске нужного значения для элемента TextBlock. Мы видим несколько безуспешных попыток определить контекст данных (DataContext), что в конечном итоге приводит к использованию значения по умолчанию {DependencyProperty.UnsetValue}, которое транслируется в пустую строку.

Использование настоящего отладчика

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

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:WpfTutorialSamples.DataBinding"
        Title="DataBindingDebuggingSample" Name="wnd" Height="100" Width="200">
	<Window.Resources>
		<self:DebugDummyConverter x:Key="DebugDummyConverter" />
	</Window.Resources>
    <Grid Margin="10">
		<TextBlock Text="{Binding Title, ElementName=wnd, Converter={StaticResource DebugDummyConverter}}" />
	</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Data;
using System.Diagnostics;

namespace WpfTutorialSamples.DataBinding
{
	public partial class DataBindingDebuggingSample : Window
	{
		public DataBindingDebuggingSample()
		{
			InitializeComponent();
		}
	}

	public class DebugDummyConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			Debugger.Break();
			return value;
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			Debugger.Break();
			return value;
		}
	}
}

В файле Code-behind мы создаём конвертер DebugDummyConverter. В методах Convert() и ConvertBack() мы вызываем метод Debugger.Break(), что приводит к такому же эффекту, что и установка точки прерывания программы в Visual Studio, с последующим возвратом неизменённого значения, полученного нами ранее.

В файле разметки мы добавляем ссылку на наш конвертер в ресурсах окна и затем используем его для привязки данных. В реальном приложении следует описывать конвертер в отдельном файле и добавлять ссылку на него в файле App.xaml, чтобы его можно было использовать в разных окнах приложения без необходимости создания ссылки в каждом окне, но для данного примера нам подойдёт и используемый подход.

Если вы запустите этот пример, вы увидите, что отладчик остановится , как только WPF попытается получить значение заголовка Window (Title). Вы можете проверить значение, переданное методу Convert(), или даже изменить его перед обработкой, используя стандартные возможности отладки Visual Studio.

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

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!