This article is currently in the process of being translated into Japanese (~97% done).
Debugging data bindings
データバインディングは実行時に評価され、失敗しても例外を投げないので、悪いバインディングは追跡がたいへん難しいことがあります。これらの問題はそれぞれの状況で異なりますが、間違ったプロパティ名を覚えているか、または単純にスペルミスするかによって、存在しないプロパティにバインドしようとするのは共通の問題です。これがサンプルです。
<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 の出力ウィンドウでしょう。それは Visual Studio ウィンドウの下の部分にあります。または [Ctrl+Alt+O] ショートカットでアクティブ化出来ます。そこにはデバッガーの出力が表示されますが、上のサンプルを走らせると、その何処かに、次のような表示が見つかるはずです。
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 という名前のグリッドで "NonExistingProperty" という名前のプロパティを使おうとしたと、言っています。これは非常に簡潔で、これが問題であれば、あなたが実際のオブジェクトにバインドしているプロパティの名前を修正する役に立ちます。
トレースレベルの調整
上のサンプルは、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" プロパティにバインドしようとしていますが、オブジェクトがありません。データコンテキストの記事で述べたように、WPFはテキストボックスの継承されたコントロールの階層を下って、 DataContext プロパティを使います。これは基本的にNULL オブジェクトのプロパティを得ようとすることを意味します。WPFはこれを、ただ単にまだ初期化されていないだけの、完全に有効なオブジェクトとみなし、エラーを出力しません。このサンプルを走らせて、Output ウィンドウを見ても、バインディングエラーはありません。
しかし、これがあなたの期待する動作でないならば、WPFにバインディングで起こった全ての問題を報告させる方法があります。それは、System.Diagnostics 名前空間にある 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.Diagnostics 名前空間の参照を加え、バインディングでプロパティを使っていることに注意してください。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が行っている全てのプロセスを確認することが出来ます。何度か適切な DataContext を見つけることが出来ず、最後は空文字列に変換されたデフォルト値 {DependencyProperty.UnsetValue} を使います。
デバッガーの使用
上記の手法は不正なバインディングの診断に役立ちますが、デバッガを使ったほうが簡単で快適な場合もあります。バインディングはWPFの内部深くで処理されているので、もともとデバッガをサポートしていませんが、以前の章で扱った Converter を使えばこのプロセスに入って行く事ができます。Converter の機能は必要ありませんが、ただ単にバインディングプロセスに入っていくためにこのダミーコンバーターを使います。
<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 のブレークポイント設定と同じ効果を持っています。そのあとパタメータの value をそのまま返します。
マークアップでは、ウィンドウリソースにあるコンバーターの参照を加え、それをバインディングで使っています。実際のアプリケーションでは、コンバーターはそれ自身があるファイルで定義し、App.xaml にその参照を追加すべきです。そうすればそれぞれのウィンドウに新しい参照を作成しなくても、アプリケーション全てからそのコンバーターを使うことが出来ます。しかしこのサンプルでは、上記で良いはずです。
このサンプルを走らせたら、WPFがウィンドウのタイトルをフェッチしようとしたところで、デバッガがブレークします。そこで Visual Studio のデバッガを使って Convert() メソッドに渡された値を調べたり、処理する前に変更したり出来ます。
デバッガがブレークしなかったら、それはコンバーターが呼ばれなかったことを意味します。これは普通、無効なバインディングを示し、この章の最初に説明した方法で診断し修正できます。ダミーコンバーターの手法は有効なバインディングにしか使えません。