TOC

This article has been localized into Spanish by the community.

Ligado de datos:

Depuración de ligaduras de datos

Teniendo en cuenta que las ligaduras de datos son evaluadas en tiempo de ejecución, y no se arrojan exepciones cuando fallan, a veces una mala ligadura puede ser muy difícil de detectar. Estos problemas pueden ocurrir en muchas situaciones diferentes, pero un problema habitual es cuando tratas de ligar a una propiedad que no existe, ya sea porque recordaste mal su nombre o porque simplemente lo escribiste mal. Aquí hay un ejemplo:

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

La Ventana de Salidas

El primer lugar donde querrás buscar es la ventana de Salidas de Visual Studio. Debería estar al fondo de tu ventana de Visual Studio, o puedes activarlo utilizando el atajo [Ctrl+Alt+O]. Ahí habrá una gran cantidad de salidas del depurador (debugger), pero en algún lado deberías encontrar una línea como esta, cuando corras el ejemplo de arriba:

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

Esto podría verse un poco abrumador, principalmente porque no se utilizan saltos de línea en mensajes largos, pero la parte importante es esta:

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

Te dice que has intentado utilizar una propiedad llamada "NonExistingProperty" en un objeto de tipo Grid, de nombre pnlMain. Es bastante conciso y debería ayudarte a corregir el nombre de la propiedad o ligar el objeto real, si ese fuera el problema.

Ajustando el nivel de rastreo

El ejemplo anterior fue fácil de arreglar, porque era claro para WPF que era lo que estábamos tratando de hacer y porque no funcionó. Sin embargo, considera el siguiente ejemplo:

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

Estoy tratando de ligar a la propiedad "Title", pero con que objeto? Como fue dicho en el artículo sobre contextos de datos, WPF utilizará la propiedad DataContext en el TextBlock aquí, que debería ser heredada a través de la jerarquía de control pero, en este ejemplo, olvidé asignarla a un contexto de datos. Esto significa básicamente que estoy intentando obtener una propiedad sobre un objeto nulo (NULL). WPF lo tomará como un ligado perfectamente válido, solo que el objeto no ha sido inicializado aún, por lo que se quejará al respecto. Si corres este ejemplo y miras en la ventana de Salidas, no verás ningún error de ligado.

De todos modos, para los casos donde este no es el comportamiento que esperas, hay una manera de forzar a WPF a avisarte sobre todos los problemas de ligado en los que incurre. Se puede hacer configurando el TraceLevel (nivel de rastreo) en el objeto PresentationTraceSources, que puede encontrarse en el espacio de nombres 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>

Notar que he añadido una referencia al espacio de nombres (namspace) System.Diagnostics al principio, y luego he usado la propiedad en el ligado. WPF ahora te dará cantidades de información sobre este ligado específico en la ventana de Salida:

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

Leyendo a través de la lista, puedes ver en realidad el proceso completo a través del que pasa WPS para hallar el valor adecuado para tu control TextBlock. Muchas veces lo verás incapaz de encontrar un DataContext adecuado, y al final, usará el DataContext por defecto {DependencyProperty.UnsetValue} que resultará en una cadena vacía.

Usando el depurador real

El truco anterior puede ser bueno para diagnosticar un mal ligado, pero en algunos casos es más fácil y agradable trabajar con el depurador de verdad. Las ligaduras no lo soportan naturalmente, ya que están siendo manejadas muy internamente por el WPF, pero utilizando un Conversor, como mostramos en el capítulo anterior, puedes saltar justo dentro de este proceso y avanzar paso a paso a través de él. No necesitas un conversor que haga algo útil en particular, solo necesitas un camino hacia el proceso de ligado, y un conversor tonto te llevará hacia allí:

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

En el archivo Code-behind, hemos definido un DebugDummyConverter. En los métodos Convert() y ConvertBack() llamamos a Debugger.Break(), que tiene el mismo efecto que poner un breakpoint en Visual Studio, y luego devuelve el valor que nos fue dado intacto.

En el archivo de marcado, hemos añadido una referencia a nuestro conversor en los recursos de la ventana y lo usamos en nuestra ligadura. En una aplicación real, deberías definir el conversor en su propio archivo y luego referenciarlo en App.xaml, de manera de poder utilizarlo a lo largo de toda la aplicación sin necesidad de crear una referencia en cada ventana, pero para este ejemplo, lo hecho funciona bien.

Si corres el ejemplo, verás que el depurador se detiene cuando WPF intenta obtener el valor para el título de la ventana. Ahora puedes inspeccionar los valores dados al método Convert(), o incluso modificarlos antes de proceder, utilizando las capacidades de depuración típicas de Visual Studio.

Si el depurador nunca se detiene, significa que el conversor no fue utilizado. Esto indica habitualmente que tienes una expresión de ligado inválida, que puede ser diagnosticada y reparada utilizando los métodos descriptos al principio de este artículo. El truco del conversor tonto es solo para probar expresiones de ligado válidas.


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!