WPF および Silverlight デザイナー読み込みエラーのトラブルシューティング
[このドキュメントはプレビューのみを目的としており、以降のリリースで変更される可能性があります。プレースホルダーとして空白のトピックが含まれています。]
WPF Designer for Visual Studio には、XAML を描画する洗練された拡張可能なビジュアル デザイナーが含まれています。 XAML ファイルがデザイナーに読み込まれない場合に、問題の原因を調べるために実行できる手順がいくつかあります。 ここでは、WPF Designer の読み込みエラーをトラブルシューティングするために役立つヒントとテクニックについて説明します。 このトピックの例では、WPF を中心に説明しますが、問題、テクニック、および解決方法のほとんどは、WPF および Silverlight に適用されます。
注意
ここで説明するテクニックの多くは、Expression Blend にも適用されます。
読み込みエラーのデバッグ
Visual Studio デバッガーを使用して、デザイン時にコードをステップ実行します。 Visual Studio の 2 番目のインスタンスを使用して、読み込みエラーをデバッグできます。 詳細については、「方法: デザイナー読み込みエラーをデバッグする」を参照してください。
トラブルシューティングの手順
次の手順は、WPF Designer の読み込みエラーをトラブルシューティングするために役立ちます。
出力された例外メッセージに目を通します。
言うまでもないことですが、例外が発生したときにはメッセージをよく読んでください。 問題のすばやい診断に役立つことがあります。 詳細については、「WPF デザイナーでのエラーのデバッグと解釈」を参照してください。
問題が実装内にあるかどうかを確認します。
アプリケーションをビルドおよび実行して、問題が実装だけに起因しているのか、WPF Designer との対話に起因しているのかを特定します。 アプリケーションをビルドおよび実行すると、実装が原因でデザイン時エラーが発生する可能性があります。
問題が読み込みエラーなのかどうかを確認します。
デザイン ビューで例外が発生して読み込みに失敗した場合、問題は読み込みエラーである可能性が高くなります。 デザイン時に読み込まれるカスタム コードがあり、例外または読み込みエラーがデザイン時に発生する場合は、このトピックの「デザイン時のコードの作成」を参照してください。
デザイン時に読み込まれるコードを校閲します。
デザイン時にも実行されるコードを作成する方法には 2 つあります。 1 つは、クラスへの入力パラメーターをチェックすることにより、防御されたコードを作成する方法です。 もう 1 つは、GetIsInDesignMode メソッドを呼び出して、デザイン モードがアクティブかどうかをチェックする方法です。 詳細については、このトピックの「デザイン時のコードの作成」を参照してください。
コードの他の領域を校閲します。
WPF Designer を操作するときのプログラミング上のヒントについては、このトピックの「プログラミングのヒント」を参照してください。 堅牢なコードを作成するテクニックについては、このトピックの「プログラミングのベスト プラクティス」を参照してください。
問題がまだ解決されない場合は、MSDN の WPF Designer フォーラム を利用して、WPF Designer を使用する他の開発者と連絡をとることができます。 懸念される問題点や提案がある場合は、Visual Studio and .NET Framework Feedback サイトへ投稿してください。
デザイン時のコードの作成
コードがデザイン時および実行時に動作することを確認します。 コードをデザイン時に実行する場合、Application.Current が常にアプリケーションであるとは限りません。 たとえば、Expression Blend の使用時は、Current は Expression Blend です。 デザイン時には、MainWindow はアプリケーションのメイン ウィンドウではありません。 デザイン時にカスタム コントロールでエラーを発生させる一般的な操作を次に示します。
Current を Application のカスタムのサブクラスにキャストした場合。
MainWindow を Window のカスタムのサブクラスにキャストした場合。
FindResource メソッドまたは FindName メソッドを Current または MainWindow に対して使用した場合。
Application.Current または Application.MainWindow が null 値を返したかどうか検査しない場合。 Visual Studio がアプリケーション オブジェクトを作成しない場合、Application.Current は null を返す可能性があります。
Assembly.GetEntryAssembly が null 値を返したかどうか検査しない場合。 Visual Studio では、このメソッドは null を返します。
デザイン時のコードを作成する方法には 2 つあります。 1 つは、値コンバーターなどのクラスへの入力パラメーターをチェックすることにより、防御されたコードを作成する方法です。 もう 1 つは、GetIsInDesignMode メソッドを呼び出して、デザイン モードがアクティブかどうかをチェックする方法です。 Silverlight には、IsInDesignTool プロパティを使用してください。
実装の入力パラメーターをチェックすることが必要な理由は、デザイン環境によって実行時環境とは異なる種類の入力が提供されるためです。
一般にスタイル セレクターと値コンバーターは、これらの方法のいずれかでデザイン時に正常に動作する必要があります。
値コンバーター
カスタムの IValueConverter 実装では、Convert メソッドの最初のパラメーターをチェックして、null または予期される型かどうかを確認する必要があります。 次の XAML は、値コンバーターが正しく実装されていない場合にデザイン時にエラーになる Application.Current へのバインディングを示しています。
<ComboBox.IsEnabled>
<MultiBinding Converter="{StaticResource specialFeaturesConverter}">
<Binding Path="CurrentUser.Rating" Source="{x:Static Application.Current}"/>
<Binding Path="CurrentUser.MemberSince" Source="{x:Static Application.Current}"/>
</MultiBinding>
</ComboBox.IsEnabled>
Application.Current がアプリケーションではなくデザイナー アプリケーションを参照するため、このバインディングはデザイン時に例外を発生させます。 この例外の発生を回避するには、値コンバーターで入力パラメーターをチェックするか、デザイン モードになっているかどうかをチェックする必要があります。
2 つの入力パラメーターが特定のビジネス ロジックを満たす場合に true を返す値コンバーターで入力パラメーターをチェックする方法を次のコード例に示します。
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Check the values array for correct parameters.
// Designers may send null or unexpected values.
if (values == null || values.Length < 2) return false;
if (!(values[0] is int)) return false;
if (!(values[1] is DateTime)) return false;
int rating = (int)values[0];
DateTime date = (DateTime)values[1];
// If the user has a good rating (10+) and has been a member for
// more than a year, special features are available.
if((rating >= 10) &&
(date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
{
return true;
}
return false;
}
2 番目の方法は、デザイン モードがアクティブかどうかをチェックするデザイン時のコードを作成することです。 前に示したパラメーターのチェックの代わりにデザイン モードのチェックを行う方法を次のコード例に示します。
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Check for design mode.
if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue))
{
return false;
}
int rating = (int)values[0];
DateTime date = (DateTime)values[1];
// If the user has a good rating (10+) and has been a member for
// more than a year, special features are available.
if((rating >= 10) &&
(date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
{
return true;
}
return false;
}
スタイル セレクター
カスタムのスタイル セレクターもデザイン モードで動作するように実装する必要があります。 次の XAML は、DataTemplate として返されるリソースを特定するために、Application.MainWindow を実行時に使用するカスタムのテンプレート セレクターを示しています。 このリソースをデザイン時に使用できない可能性があるため、SelectTemplate オーバーライドはデザイン時に null を返します。
<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}"
ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
HorizontalContentAlignment="Stretch"
IsSynchronizedWithCurrentItem="True"/>
スタイル セレクターの実装例を次のコードに示します。
public class TaskListDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(
object item,
DependencyObject container)
{
if (item != null && item is Task)
{
Task taskitem = item as Task;
Window window = Application.Current.MainWindow;
// To run in design mode, either test for the correct window class
// or test for design mode.
if (window.GetType() == typeof(MainWindow))
// Or check for design mode:
//if (!DesignerProperties.GetIsInDesignMode(window))
{
if (taskitem.Priority == 1)
return window.FindResource("importantTaskTemplate") as DataTemplate;
else
return window.FindResource("myTaskTemplate") as DataTemplate;
}
}
return null;
}
}
プログラミングのヒント
WPF Designer を操作するときのプログラミングのヒントを次に示します。
カスタム コントロールを WPF Designer に読み込む必要がある場合は、定義済みの依存関係プロパティの CLR get メソッドと set メソッドを用意する必要があります。 詳細については、「カスタム依存関係プロパティ」を参照してください。
ComboBox 型の修飾はサポートされていません。
サードパーティの Windows フォーム コントロールを使用するには、Controls コレクション内にベンダー コントロールのインスタンスを持つ UserControl 型を作成します。 詳細については、「チュートリアル : サードパーティの Windows フォーム コントロールの WPF アプリケーションでのホスト」を参照してください。
FlowDocument のデザイン時は直接サポートされません。 埋め込まれた FlowDocument で WPF Designer を使用する場合は、まず FlowDocument を Frame コントロールに配置し、次にこれを WPF Designer 内で使用します。
プログラミングのベスト プラクティス
ここでは、WPF Designer 用の堅牢なコードを作成するためのプログラミングのベスト プラクティスをいくつか示します。
編集スコープは、using ステートメントまたは try/finally ブロックで常にラップします。 例外が発生すると、Dispose 呼び出し内で変更が中止されます。 詳細については、「ModelEditingScope」を参照してください。
1 つのコンテナーから別のコンテナーにコントロールを移動するには ModelEditingScope を使用します。 これを行わない場合、例外が発生します。
WPF および WPF Designer では、プロパティ値をクリアする目的で既定値に設定しないでください。 Height などに NaN 値を設定する場合は、NaN を代入するのではなく ClearValue メソッドを呼び出します。
プロパティの値を取得するには、プロパティの計算値を使用します。 つまり、ModelItem の GetCurrentValue メソッドではなく ComputedValue プロパティを使用する必要があります。 GetCurrentValue メソッドは、バインディングやその他の式が XAML に保存された場合にこれらを返すため、キャスト例外が発生することがあります。