This article is currently in the process of being translated into Croatian (~99% done).
Debugging data bindings
S obzirom da se poveznice evaluiraju tijekom izvođenja i ne bacaju se iznimke ako dođe do greške, loše povezivanje može ponekad biti teško za ustanoviti. Problemi mogu nastati u nekoliko različitih situacija, ali uobičajeni problem je kada pokušate nešto povezati sa svojstvom koje ne postoji, ili zato jer ste krivo zapamtili ime ili ste ga jednostavno krivo napisali. Evo primjera:
<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 prozor
Prvo mjesto na koje ćete poželjeti pogledati je Output prozor u Visual Studiju. Trebao bi se nalaziti na dnu vašeg Visual Studio prozora ili ga možete aktivirati korištenjem [Ctrl+Alt+O] kratice. U tom prozoru ćete naći gomilu ispisa od strane debuggera, ali bi se negdje trebala naći i linija poput ove, kada pokrenete gornji kod:
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')
Ovo može izgledati pomalo zastrašujuće, uglavnom zato što se u ovoj dugoj poruci ne koriste prijelomi redaka, ali važno je ovo:
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.
Ovo vam govori da ste pokušali koristiti svojstvo imena "NonExistingProperty" na objektu tipa Grid i imena pnlMain. To je poprilično koncizno i trebalo bi vam pomoći da ispravite ime svojstva ili da se povežete sa stvarnim objektom, ako je to problem.
Podešavanje razine praćenja
Gornji je primjer bio jednostavan za popraviti jer je WPF-u bilo jasno što smo pokušavali napraviti i zašto to nije radilo. Razmotrimo ovaj primjer:
<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>
Pokušavam povezati "Title" svojstvo, ali s kojim objektom? Kao što je navedeno u članku o kontekstu podataka WPF će koristiti DataContext svojstvo na TextBlocku koje se može naslijediti niz hijerarhiju kontrola, ali u ovom primjeru, zaboravio sam dodijeliti kontekst podataka. To u osnovi znači da pokušavam dohvatiti svojstvo na NULL objektu. WPF će shvatiti da je ovo možda savršeno točno povezivanje, ali da objekt jednostavno još uvijek nije inicijaliziran i zbog toga se neće buniti. Ako pokrenete ovaj primjer i pogledate u Output prozor, nećete vidjeti nikakve greške povezivanja.
Međutim, u slučajevima kada ovo nije ponašanje koje očekujete, postoji način da se WPF natjera da vam kaže na koje je probleme naišao prilikom povezivanja. To se može napraviti postavljanjem TraceLevela na PresentationTraceSources objektu koji se nalazi u System.Diagnostics imenovanom prostoru:
<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>
Primijetite da sam na vrhu dodao referencu na System.Diagnostics imenovani prostor i onda sam iskoristio svojstvo nad poveznicom. WPF će sada u Output prozoru dati velike količine informacija o specifičnoj poveznici:
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 ''
Čitajući ispis, zapravo možete vidjeti cijeli proces kroz koji WPF prolazi pokušavajući pronaći odgovarajuću vrijednost za vašu TextBlock kontrolu. Više puta ćete vidjeti da nije u mogućnosti pronaći odgovarajući DataContext i na kraju koristi podrazumijevanu vrijednost {DependencyProperty.UnsetValue} koja se prevodi u prazni string.
Korištenje pravog debuggera
Gornji trik može uvelike pomoći za dijagnosticiranje lošeg povezivanja, ali u nekim je slučajevima jednostavnije i ugodnije raditi s pravim debuggerom. Povezivanja izvorno ne podržavaju ovo jer se njima upravlja duboko unutar WPF-a, ali korištenjem konvertera, kako je pokazano u jednom od prethodnih članaka, možete uskočiti u proces i prolaziti kroz njega. Ne treba vam konverter koji radi nešto korisno, treba vam samo način da se ubacite u proces povezivanja i dummy konverter će vam u tome pomoći:
<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;
}
}
}
U pozadinskom kodu definiramo DebugDummyConverter. U Convert() i ConvertBack() metodama pozivamo Debugger.Break(), što ima isti učinak kao postavljanje breakpointa u Visual Studiju i onda kao povratnu vrijednost vraćamo vrijednost koja je proslijeđena metodama, bez da ju mijenjamo.
U markup dijelu smo dodali referencu na naš konverter u resurse prozora i onda ga koristimo u našoj poveznici. U stvarnoj aplikaciji biste trebali definirati konverter u vlastitoj datoteci i onda dodati referencu na njega u App.xaml, tako da ga možete koristiti unutar cijele aplikacije bez potrebe da kreirate novu referencu unutar svakog prozora, ali za ovaj primjer je ovo sasvim dovoljno.
Ako sada pokrenete primjer, vidjet ćete da debugger prekida izvođenje čim WPF pokuša dohvatiti vrijednost za naslov prozora. Sada možete pregledati vrijednosti koje su proslijeđene Convert() metodi i čak ih i izmijeniti prije no što nastavite, uz pomoć standardnih mogućnosti debuggiranja u Visual Studiju.
Ako se debugger nikad ne zaustavi, to znači da se konverter ne koristi. To obično znači da imate neispravan izraz za povezivanje, a to se može dijagnosticirati i popraviti pomoću metoda opisanih na početku ovog članka. Trik s dummy konverterom se koristi samo za testiranje ispravnih izraza za povezivanje.