This article has been localized into Portuguese by the community.
Debugando data bindings
Como as vinculações de dados são avaliadas no tempo de execução, e nenhuma exceção é lançada quando elas falham, às vezes é muito difícil rastrear uma vinculação incorreta. Esses problemas podem ocorrer em várias situações diferentes, mas um problema comum é quando você tenta vincular a uma propriedade que não existe, porque você se lembrou do nome errado ou porque simplesmente digitou errado. Aqui está um exemplo:
<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>
A janela Output
O primeiro lugar que você vai querer olhar é a janela de Output do Visual Studio. Ele deve estar na parte inferior da sua janela do Visual Studio, ou você pode ativá-lo usando o atalho [Ctrl + Alt + O]. Haverá muitas saídas do depurador, mas em algum lugar você deve encontrar uma linha como essa, ao executar o exemplo acima:
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')
Isso pode parecer um pouco esmagador, principalmente porque nenhuma quebra de linha é usada nesta longa mensagem, mas a parte importante é esta:
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.
Ele informa que você tentou usar uma propriedade chamada "NonExistingProperty" em um objeto do tipo Grade, com o nome pnlMain. Isso é bastante conciso e deve ajudá-lo a corrigir o nome da propriedade ou vincular-se ao objeto real, se esse for o problema.
Ajustando o nível de rastreio
O exemplo acima foi fácil de corrigir, porque ficou claro para o WPF o que estávamos tentando fazer e por que não funcionou. Mas considere o próximo exemplo:
<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>
Eu estou tentando ligar a propriedade "Title", mas em qual objeto? Como declarado no artigo sobre contextos de dados, o WPF usará a propriedade DataContext no TextBlock aqui, que pode ser herdada na hierarquia de controle, mas neste exemplo, esqueci de atribuir um contexto de dados. Isso basicamente significa que estou tentando obter uma propriedade em um objeto NULL. O WPF reunirá que isso pode ser uma ligação perfeitamente válida, mas que o objeto ainda não foi inicializado e, portanto, não se queixará disso. Se você executar este exemplo e procurar na janela Output, não verá nenhum erro de ligação.
No entanto, para os casos em que esse não é o comportamento esperado, há uma maneira de forçar o WPF a informá-lo sobre todos os problemas de ligação em que ele se depara. Isso pode ser feito definindo o TraceLevel no objeto PresentationTraceSources, que pode ser encontrado no namespace 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>
Observe que eu adicionei uma referência ao namespace System.Diagnostics na parte superior e usei a propriedade na ligação. O WPF agora fornecerá muitas informações sobre essa ligação específica na janela 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 ''
Ao ler a lista, você pode realmente ver todo o processo pelo qual o WPF passa para tentar encontrar um valor adequado para o seu controle TextBlock. Várias vezes você verá que é impossível encontrar um DataContext adequado e, no final, ele usa o padrão {DependencyProperty.UnsetValue} que se traduz em uma string vazia.
Usando o depurador real
O truque acima pode ser ótimo para diagnosticar uma má ligação, mas, em alguns casos, é mais fácil e mais agradável trabalhar com o depurador real. Os bindings não suportam isso nativamente, já que eles estão sendo manipulados dentro do WPF, mas usando um conversor, como mostrado em um artigo anterior, você pode realmente entrar nesse processo e passar por ele. Você realmente não precisa de um Conversor que faça algo útil, você só precisa entrar no processo de binding, e um conversor fictício o levará até lá:
<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;
}
}
}
No arquivo Code-behind, definimos um DebugDummyConverter. Nos métodos Convert() e ConvertBack(), chamamos Debugger.Break(), que tem o mesmo efeito que definir um ponto de interrupção no Visual Studio e, em seguida, retornar o valor que nos foi dado.
Na marcação, adicionamos uma referência ao nosso conversor nos recursos da janela e, em seguida, usamos em nosso binding. Em um aplicativo do mundo real, você deve definir o conversor em um arquivo próprio e, em seguida, adicionar a referência a ele no App.xaml, para que você possa usá-lo em todo o aplicativo sem precisar criar uma nova referência para ele em cada janela, mas para este exemplo, a solução acima deve funcionar muito bem.
Se você executar o exemplo, verá que o depurador quebra assim que o WPF tenta buscar o valor para o título da janela. Agora você pode inspecionar os valores fornecidos ao método Convert() ou até mesmo alterá-los antes de prosseguir, usando os recursos de depuração padrão do Visual Studio.
Se o depurador nunca quebrar, isso significa que o conversor não é usado. Isso geralmente indica que você tem uma expressão de binding inválida, que pode ser diagnosticada e corrigida usando os métodos descritos no início deste artigo. O truque do conversor fictício é apenas para testar expressões de binding válidas.