This article has been localized into Bulgarian by the community.
Debug на обвързването на данни
Тъй като обвързванията на данни се оценяват по време на изпълнение на програмата и не се хвърлят изключения, когато има проблем, неправилното обвързване понякога може да бъде много трудно за проследяване. Тези проблеми могат да възникнат в няколко различни ситуации, но често срещан проблем е, когато се опитате да се свържете към свойство, което не съществува, или защото сте запомнили името му погрешно, или защото просто сте го написали грешно. Ето един пример:
<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" прозорец
Първото място, което ще трябва да погледнете, е прозорецът "Output" на 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. Това всъщност е доста ясно и трябва да ви помогне да коригирате името на свойството или да се свържете с реалния обект, ако това е проблемът.
Нагласяне на нивото на проследяване
Горният пример беше лесен за коригиране, защото на 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 тук, което може да бъде наследено надолу по контролната йерархия, но в този пример забравих да присвоя "DataContext.this". Това означава, че се опитвам да получа свойство на NULL обект. WPF ще разбере, че това може да е напълно валидно обвързване, но че обектът просто все още не е инициализиран и следователно няма да се оплаква от това. Ако стартирате този пример и погледнете в прозореца за Output, няма да видите никакви грешки при обвързване.
Въпреки това, за случаите, когато това не е поведението, което очаквате, има начин да принудите WPF да ви съобщи за всички проблеми със свързването, с които се сблъсква. Това може да стане чрез задаване на TraceLevel на обекта PresentationTraceSources, който може да се намери в System.Diagnostics namespace:
<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 namespace-а в горната част и след това използвах свойството на обвързването. 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} по подразбиране, което се превежда в празен низ.
Използване на истински debugger
Горният трик може да бъде чудесен за диагностициране на лошо свързване, но в някои случаи е по-лесно и по-приятно да се работи с истинския дебъгер. Обвързванията не поддържат това първоначално, тъй като те се обработват дълбоко в 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;
}
}
}
Във файла с кода ние дефинираме DebugDummyConverter. В методите Convert() и ConvertBack() извикваме Debugger.Break(), което има същия ефект като задаването на "breakpoint" във Visual Studio, и след това връщаме стойността, която ни е дадена непроменена.
В markup частта (с { } скоби) добавяме препратка към нашия конвертор в ресурсите на прозореца и след това го използваме в нашето обвързване. В приложение от реалния свят трябва да дефинирате конвертора в негов собствен файл и след това да добавите препратката към него в App.xaml, така че да можете да го използвате навсякъде в приложението, без да се налага да създавате нова препратка към него във всяко прозорец, но за този пример горното следва да е достатъчно.
Ако изпълните примера, ще видите, че програмата за debugger-а прекъсва веднага щом WPF се опита да извлече стойността за заглавието на прозореца. Вече можете да проверите стойностите, дадени на метода Convert(), или дори да ги промените, преди да продължите, като използвате стандартните възможности на debugger-а на Visual Studio.
Ако дебъгерът никога не спре, това означава, че конверторът не е използван. Това обикновено показва, че имате невалиден обвързващ израз, който може да бъде диагностициран и коригиран с помощта на методите, описани в началото на тази статия. Трикът с фиктивен конвертор е само за тестване на валидни обвързващи изрази.