TOC

This article has been localized into Polish by the community.

Powiązanie danych:

Debugowanie wiązania danych

Ponieważ powiązania danych są oceniane w czasie działania programu i żadne wyjątki nie są generowane, gdy się nie powiodą, wyśledzenie złego powiązania danych może być czasami bardzo trudne. Takie problemy mogą wystąpić w kilku różnych sytuacjach, ale często występującą sytuacją jest próba powiązania do właściwości, która nie istnieje, ponieważ zapamiętałeś jej nieprawidłową nazwę lub po prostu błędnie ją wpisałeś. Oto przykład:

<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>

Okno Output

Pierwszym miejscem, w które możemy zajrzeć, jest okno danych wyjściowych (Output window) programu Visual Studio. Powinno znajdować się ono u dołu okna programu Visual Studio lub można je aktywować za pomocą skrótu [Ctrl + Alt + O]. Pojawią się tam dane wyjściowe z debuggera, ale gdy uruchomisz omawiany wyżej przykład gdzieś pośród nich powinieneś znaleźć taką linię:

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')

Może wydawać się ona nieco przytłaczająca, głównie dlatego, że w tej długiej wiadomości nie jest stosowany zapis w wielu wielowierszowy, ale ważne jest to:

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

Komunikat ten mówi ci, że próbowałeś użyć właściwości o nazwie „NonExistingProperty” na elemencie typu Grid o nazwie "pnlMain". W rzeczywistości jest to dość zwięzłe i powinno pomóc ci poprawić nazwę właściwości lub powiązać dane z rzeczywistym obiektem, jeśli w tym tkwi problem.

Ustawienie TraceLevel

Powyższy przykład był łatwy do naprawienia, ponieważ dla WPF było jasne, co próbujemy zrobić i dlaczego to nie działa. Rozważ jednak następny przykład:

<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>

Próbuję powiązać dane z właściwością „Title”, ale którego obiektu? Jak stwierdzono wcześniej w artykule na temat wiązania danych, WPF użyje tutaj właściwości "DataContext" zdefiniowanej bezpośrednio w kontrolce "TextBlock" lub najbliższej kontrolce znajdującej się wyżej w hierarchii drzewa kontrolek, ale w tym przykładzie zapomniałem przypisać "DataContext". Zasadniczo oznacza to, że próbuję uzyskać właściwość obiektu NULL. WPF uzna, że jest to całkowicie poprawne powiązanie, ale obiekt po prostu nie został jeszcze zainicjowany i dlatego nie będzie narzekał. Jeśli uruchomisz ten przykład i spojrzysz w okno Output, nie zobaczysz żadnych błędów powiązań danych.

Jednak w przypadkach, w których nie jest to zachowanie jakiego oczekujesz, istnieje sposób, aby zmusić WPF do informowania Cię o wszystkich napotkanych problemach dotyczących powiązania danych. Można to zrobić, nastawiając właściwość TraceLevel w obiekcie PresentationTraceSources, który znajduje się w przestrzeni nazw 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>

Zwróć uwagę, że dodałem odwołanie do przestrzeni nazw System.Diagnostics w górnej części kodu XAML, a następnie użyłem wspomnianej właściwości bezpośrednio w definicji powiązania danej. WPF poda teraz mnóstwo informacji o tym konkretnym powiązaniu danej w oknie 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 ''

Czytając ową listę, możesz faktycznie zobaczyć cały proces, przez który przechodzi WPF, próbując znaleźć odpowiednią wartość źródłową dla kontrolki TextBlock. Kilka razy zobaczysz, że nie może znaleźć odpowiedniego DataContext, a na końcu używa domyślnego {DependencyProperty.UnsetValue}, co WPF tłumaczy sobie na pusty łańcuch znaków.

Korzystanie z prawdziwego debuggera

Powyższa sztuczka może być świetna do diagnozowania złego powiązania danych, ale w niektórych przypadkach praca z prawdziwym debugger'em jest zwyczajnie łatwiejsza i przyjemniejsza. Procesy powiązania danych nie są domyślnie sprawdzane przez debugger'a, ponieważ są obsługiwane głęboko w WPF, ale używając konwertera wartości, jak pokazano we wcześniejszym artykule, możesz tak napradę wskoczyć do takiego procesu i w całości przez niego przejść. Właściwie nie potrzebujesz konwertera wartości, który robi cokolwiek pożytecznego, a potrzebujesz jedynie dostępu do procesu wiązania danych, a fałszywy konwerter wartości cię tam doprowadzi:

<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;
		}
	}
}

W kodzie pliku CodeBehind definiujemy klasę konwentera "DebugDummyConverter". W jej metodach Convert() oraz ConvertBack() wywołujemy metodę Debugger.Break(), co daje identyczny efekt, jak ustawienie punktu przerwania (Breakpoint) w programie Visual Studio, a następnie zwracamy wartość, która została nam przekazana w postaci nietkniętej.

W pliku XAML w zasobach okna aplikacji dodajemy odniesienie do naszego konwertera, a następnie używamy go w naszym powiązaniu danych. W prawdziwej aplikacji należy zdefiniować konwerter w osobnym pliku, a następnie dodać odniesienie do konwertera w pliku XAML "App.xaml", dzięki czemu będzie go można używać w całej aplikacji bez konieczności tworzenia nowego odniesienia do niego w każdym oknie, ale na potrzeby tego przykładu wystarczy powyższe rozwiązanie.

Gdy uruchomisz nasz przykład, zobaczysz, że debugger przerywa pracę aplikacji, gdy tylko WPF spróbuje pobrać wartość Title okna. Możesz teraz sprawdzić wartości przekazane metodzie Convert(), lub nawet zmienić je przed kontynuowaniem, korzystając ze standardowych funkcji debugowania programu Visual Studio.

Jeżeli debugger nigdy nie przerywa pracy aplikacji, oznacza to, że konwerter nie jest używany. Zwykle oznacza to, że masz nieprawidłowo zdefiniowane powiązanie danych, które można zdiagnozować i naprawić za pomocą sposobów opisanych na początku tego artykułu. Sztuczka z fałszywym konwerterem służy tylko do testowania poprawnie zdefiniowanych powiązań danych.


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!