This article is currently in the process of being translated into Korean (~98% done).
Debugging data bindings
data binding은 프로그램 실행 시간에 평가되고, 실패해도 예외가 던져지지 않는 이유로, 잘못된 바인딩을 추적하기 상당히 어려울 수 있다. 이러한 문제들은 몇몇 다른 상황들에서도 일어날 수 있지만, 일상적으로 없는 속성에 바인딩을 시도하거나, 속성의 이름을 잘 못 기억했거나,철자법이 틀릴 때에 발생한다. 아래에 예가 있다.
<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>
출력창
확인할 첫번째 위치는 Visual Studio Output 창이다. Visual Studio 창의 아랫 부분에 위치해 있는데 없으면 [Ctrl+Alt+O] 단축키로 활성화 할 수 있는 창이다. Debugger로 인해 출력 결과가 쏟아 지지만, 위와 같은 잘 못된 예시 프로그램이 실행될때엔 다음과 같은 줄을 찾을려고 노력해야 한다.
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')
이 긴 줄에 줄바꿈도 없으니 약간 질리게 보일지도 모르겠지만 중요한 부분은 이 부분이다:
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.
이것은 당신이 pnlMain이라는 이름을 가진, Grid 타입의 객체에서 "NonExistingProperty"로 불리는 속성을 사용할려고 시도했음을 말해줍니다. 이것은 실재로 상당히 간결하고 당신이 속성명을 수정하거나 문제되는 실제 객체와 바인드하는 것을 도와주게 됩니다.
Adjusting the trace level
위의 예는 WPF에게 프로그래머가 뭘 할려고 하고 왜 그것이 동작하지 않는지가 명확하기 때문에 수정하기 쉬운 편입니다. 그렇지만 다음 예를 한번 생각해보세요.
<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>
"Title" 속성을 바인드 할려고 시도했지만 객체가 어디에 있나요? data context에 대한 글에서 말했듯이,WPF는 여기 TextBlock에는 DataContext 속성을 사용하는데,그것은 control 계층에서 상속받을 것입니다. 그러나 이 예제에서 data context를 할당하는 걸 잊어버렸습니다. 이것은 기본적으로 프로그래머가 NULL 객체의 속성을 얻을려고 시도하고 있다는 걸 의미합니다. WPF는 이 프로그램이 완벽히 유효한 바인딩이라고 이해할 거지만, 객체가 아직 초기화되지 않았고, 그래서 WPF는 문제가 있다고 말하지 않을 것입니다. 당신이 이 예제를 실행하고 Output 창을 들여다 봐도 어떤 binding 오류는 보지 못할 것입니다.<
그렇지만,당신이 기대한 동작이 아닌 경우에 WPF로 하여금 그것이 부딪치는 binding 문제를 강제로 보여주게 하는 방법이 있습니다. 그건 System.Diagnostics namespace에 있는 PresentationTraceSources 객체에 TraceLevel을 설정하는걸로 할 수 있습니다.
<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>
제일 상단에 System.Diagnostic namespace에 대한 참조를 추가하고 binding에 그 속성을 사용한 걸 눈여겨 보세요. WPF는 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 ''
목록을 읽어보면, WPF가 TextBlock 컨트롤에 대한 적절한 값을 찾으려고 시도하는 전체 과정을 실제로 볼 수 있습니다. 여러 번에 걸쳐 적절한 DataContext를 찾을 수 없는 것을 볼 수 있으며, 결국에는 기본값인 {DependencyProperty.UnsetValue}를 사용하는데, 이는 빈 문자열로 변환됩니다.
Using the real debugger
위의 트릭은 잘못된 바인딩을 진단하는 데 큰 도움이 될 수 있지만, 경우에 따라서는 실제 디버거를 사용하는 것이 더 쉽고 편리할 수 있습니다. 바인딩은 WPF의 내부 깊숙이 처리되기 때문에 기본적으로 이를 지원하지 않습니다. 그러나 이전 문서에서 보여준 것처럼 컨버터를 사용하면 실제로 이 프로세스로 들어가서 단계별로 진행할 수 있습니다. 실제로 유용한 작업을 수행하는 컨버터가 꼭 필요한 것은 아닙니다. 단지 바인딩 프로세스로 들어갈 수 있는 방법이 필요할 뿐이며, 더미 컨버터를 사용하면 이를 달성할 수 있습니다:
<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;
}
}
}
코드 숨김 파일에서 DebugDummyConverter를 정의합니다. Convert()와 ConvertBack() 메서드에서는 Debugger.Break()를 호출하는데, 이는 Visual Studio에서 중단점을 설정하는 것과 동일한 효과를 가집니다. 그런 다음 주어진 값을 그대로 반환합니다.
마크업에서는 윈도우 리소스에 컨버터에 대한 참조를 추가한 다음, 바인딩에서 해당 컨버터를 사용합니다. 실제 애플리케이션에서는 컨버터를 별도의 파일에 정의하고 App.xaml에 해당 참조를 추가하는 것이 좋습니다. 이렇게 하면 각 윈도우에서 새로운 참조를 만들 필요 없이 애플리케이션 전체에서 컨버터를 사용할 수 있습니다. 그러나 이 예제에서는 위의 방법으로도 충분할 것입니다.
예제를 실행하면 WPF가 윈도우의 제목에 대한 값을 가져오려고 시도하는 즉시 디버거가 중단되는 것을 볼 수 있습니다. 이제 Visual Studio의 표준 디버깅 기능을 사용하여 Convert() 메서드에 전달된 값을 검사하거나, 진행하기 전에 값을 변경할 수도 있습니다.
만약 디버거가 중단되지 않는다면, 이는 컨버터가 사용되지 않는다는 것을 의미합니다. 이는 일반적으로 잘못된 바인딩 표현식이 있음을 나타내는데, 이 문서의 시작 부분에서 설명한 방법을 사용하여 진단하고 수정할 수 있습니다. 더미 컨버터 트릭은 유효한 바인딩 표현식을 테스트하는 데에만 사용됩니다.