This article has been localized into Danish by the community.
Fejlsøgning i databindinger
Eftersom databindinger evalueres run time, og der ikke bliver udløst nogle undtagelser, når de mislykkes, kan en dårlig binding nogle gange være svær at finde. Disse problemer kan opstå i mange forskellige situationer, men et generelt problem er, når du forsøger at binde til en egenskab, der ikke findes - enten fordi, du husker navnet forkert, eller fordi du har stavet det forkert. Her er et eksempel:
<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 vinduet
Det første sted, du vil kikke, er Visual Studio Output vinduet. Det burde blive vist i bunden af dit Visual Studio vindue, eller du kan aktiveret det med [Ctrl+Alt+O] genvejen. Der vil være masser af output fra debuggeren, men et eller anden sted vil du finde en linje som denne, når du kører eksemplet ovenfor:
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')
Det kan virke overvældende, primært fordi, der ikke er brugt linjeskift i den lange besked. Men den væsentlige del er denne:
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.
Det fortæller dig, at du har prøvet at bruge en egenskab kaldet "NonExistingProperty" på et objekt af typen Grid, med navnet pnlMain. Det er faktisk ret præcist og burde hjælpe dig med at rette navnet på egenskaben eller binde til det reelle objekt, hvis det er problemet.
Justering af trace-niveau
Ovenstående eksempel var nemt at rette, fordi det var tydeligt for WPF hvad, vi forsøgte at gøre, og hvorfor, det ikke virkede. Men hvad med dette eksempel:
<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>
Jeg prøver her at binde til "Title" egenskaben, men på hvilket objekt? Som nævnt i artiklen om datakontekst vil WPF bruge DataContext egenskaben på TextBlock her. Den kan være arvet ned igennem kontrolhierarket, men i dette eksempel glemte jeg at tildele en datakontekst. Dette betyder, at jeg prøver at binde en egenskab på et NULL objekt. WPF vil mene, at dette er en ganske valid binding, men objektet er bare ikke initialiseret endnu, og derfor vil den ikke klage over det. Hvis du kører eksemplet og ser i Output vinduet, vil du ikke se nogle bindingsfejl.
I tilfælde som dette, hvor det ikke er den forventede opførsel, er der en måde at tvinge WPF til at fortælle dig om alle bindingsproblemer, der måtte opstå. Det kan gøres ved at sætte TraceLevel på PresentationTraceSources objektet, som findes i namespacet 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>
Bemærk, at jeg har tilføjet en reference til namespacet System.Diagnostics i toppen, og derefter benytter egenskaben på bindingen. WPF vil nu give dig bunker af information om denne specifikke binding i Output vinduet:
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 ''
Ved at gennemgå listen, kan du faktisk se hele den proces, som WPF går igennem for at finde en anvendelig værdi til din TextBlock kontrol. Flere gange vil du se, at den ikke er i stand til at finde en brugbar DataContext, og til slut vil den bruge standardværdien (DependencyProperty.UnsetValue), som omdannes til en tom streng.
Brug af den ægte debugger
Tricket ovenfor kan være storarted til at diagnostisere en dårlig binding, men i nogle tilfælde er det lettere og mere behageligt at arbejde med den rigtige debugger. Bindinger understøtter ikke dette direkte, eftersom de bliver håndteret dybt nede i WPF, men ved hjælp af en konvertering som den vist i en tidligere artikel, kan du faktisk springe ind i den proces og gå den igennem trinvis. Du behøver reelt ikke en konvertering, som gør noget brugbart - du har bare brug for en vej ind i bindingsprocessen, og en dummy konvertering vil gøre dette:
<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;
}
}
}
I code-behind filen definerer vi en DebugDummyConverter. I Convert() og ConvertBack() metoderne kalder vi Debugger.Break(), hvilket har den samme effekt som at sætte et breakpoint i Visual Studio, og derfra returnerer vi værdien, vi fik ind, uden at ændre den.
I markup tilføjer vi en reference til konverteringen i vinduesressourcerne, og derefter kan vi bruge den i vores bindinger. I en reel applikation bør du definere konverteringen i sin egen fil og derefter tilføje referencen til den i App.xaml, så du kan bruge den i hele applikationen uden at være nødt til at lave en reference til den i hvert eneste vindue, men til dette eksempel er ovenstående ganske udmærket.
Hvis du prøver at køre eksemplet, vil du se, at debuggeren afbryder så snart, WPF prøver at hente værdien til vinduestitlen. Du kan nu inspicere den værdi (value parameteren), der blev sendt til Convert() methoden, eller endda ændre dem før, koden fortsættes, ved hjælp af de almindelige debugging faciliteter i Visual Studio.
Hvis debuggeren ikke afbryder, betyder det, at konverteringen ikke bruges. Dette indikerer normalt, at du har et ugyldigt bindingsudtryk, hvilket kan diagnostiseres og rettes ved hjælp af metoderne beskrevet i starten af artiklen. Dummy-konverteringstricket er kun til at teste gyldige bindingsudtryk.