原文
WPF Localization Guidance 「Rick StrahlとMichele Leroux Bustamante(2009年6月)」の和訳です。地域設定の実装の参考にしてください。
関連ファイル
カスタム・マークアップ拡張機能は、どのように動作するか
How the Custom Markup Extension Works
ResExtensionの実装は、簡単です。それは、背後で、直接リソースを取得する、1つ以上のResourceManagerインスタンスを使用します。 そして、それらに、マークアップ拡張機能の構文を使用する結合によって、XAMLドキュメントを提供します。 一旦、リソース値を取得した型であれば、変換は、文字列の値を、プロパティ型を取得したマークアップ拡張機能が結合している値に、一致させるために適用されます。 マークアップ拡張機能の前提は、すべての値が文字列値であるということです。利用できる場合、それは、結合したプロパティの値コンバータによって送られます。 全体の処理は、エラー処理ブロックによりラップされます。それは、どんな結合のエラーでも捕えて、Default値の表示に戻します。 エラーが発生する場合、また、エラーは、Trace出力に書き込まれます。 それをデバッグモードで実行するとき、あなたは、Output Windowを使用して、Visual Studioでモニターすることができます。
FIGURE 21:
ResExtensionカスタム拡張機能は、リソースを取得するために、直接、ResourceManagerインスタンスを使用します。 そして、XAMLドキュメントにそれらを供給します。
ここにある、マークアップ拡張機能の全体を説明するのは、この記事の範囲を越えています。 しかし、あなたに、マークアップ拡張機能に必要な考えを与えます。 そして、ResExtensionが、Figure 22で与える値で、どのように動作するかは、ProvideValueInternal関数(簡略化された)に示します。 それは、ほとんどの操作を処理します。
FIGURE 22:
ResExtensionマークアップ拡張機能の、重要なProvideInternalメソッドは、リソースの検索、書式設定と必要に応じてエラー処理を処理する中心的なメソッドです。
private object ProvideValueInternal()
{
object localized = null;
if (Static == null)
{
// Get a new or cached resource manager for this resource set
// このリソース・セットのための、新しい、あるいは、
// キャッシュに格納されたリソースマネージャを手に入れます。
ResourceManager resMan = this.GetResourceManager(this.ResourceSet);
// Get the localized value
// 地域設定された値を手に入れます。
if (resMan != null)
localized = resMan.GetObject(this.Id);
}
else
{
try
{
// Parse Static=properties:Resources.HelloWorld
int index = this.Static.IndexOf('.');
if (index == -1)
throw new ArgumentException();
// resolve properties:Resources
//プロパティ:Resourcesを解決します
string typeName = this.Static.Substring(0, index);
IXamlTypeResolver service =
_serviceProvider.GetService(typeof(IXamlTypeResolver))
as IXamlTypeResolver;
Type memberType = service.Resolve(typeName);
string propName = this.Static.Substring(index + 1);
localized = memberType.GetProperty(propName,
BindingFlags.Public | BindingFlags.Static |
BindingFlags.FlattenHierarchy)
.GetValue(memberType, null);
}
catch
{ /* ignore retrieval errors */ }
{/*検索エラーを無視します*/}
}
// If the value is null, use the Default value if available
// 値がnullの場合、もし、利用できれば、Default値を使用します。
if (localized == null && this.Default != null)
localized = this.Default;
// fail type conversions silently and write to trace output
// 型変換は静に失敗し、トレース出力に書き込まれます
try
{
// Convert if a type converter is availalbe
// 型コンバータが利用できる場合、変換します
if (localized != null &&
this.Converter == null &&
_typeConverter != null &&
_typeConverter.CanConvertFrom(localized.GetType()))
localized = _typeConverter.ConvertFrom(localized);
// Apply a type converter if one was specified
// 1つが指定された場合、型コンバータを適用します
if (Converter != null)
localized = this.Converter.Convert(localized,
_targetProperty.PropertyType,
null, CultureInfo.CurrentCulture);
}
catch (Exception ex)
{
Trace.WriteLine(string.Format( Resources.ConversionErrorMessageFormatString,
Id, ex.Message));
localized = null;
}
// If no fallback value is available, return the key
// 代替システムの値が利用できるない場合、キーを返します
if (localized == null)
{
if (_targetProperty != null &&
_targetProperty.PropertyType == typeof(string))
localized = string.Concat("?", Id, "?");
else
return DependencyProperty.UnsetValue;
}
// Format if a format string was provided
// 書式設定文字列が与えられた場合、書式を設定します
if (this.Format != null)
localized = string.Format(CultureInfo.CurrentUICulture,
this.Format, localized);
return localized;
}
マークアップ拡張機能は、それらを結合するために、コントロールとプロパティに関する情報を受け取ります。 それは、結合されたコントロール・オブジェクト・インスタンスと依存関係プロパティを与えます。 また、依存関係プロパティに基づいて、あなたは、型コンバータを取得することができます。 それは、文字列から適切なプロパティ型に、値を変換できます。 これらの参照は、ResourceManagerから取得される文字列に基づいて、値を設定するために使用することができます。
マークアップ拡張機能は、先程、説明した、プロパティを持っています。(ID、ResourceSet、Defaultなど) そして、これらのプロパティに基づいて、コードは、適切なResourceManagerとリソースIDを取得することを試みます。 一旦、値が取得されると、型コンバータは、適切に、その書式の設定を適用することができます。 エラーの発生、あるいは、リソースIDの検索が失敗した場合、一般的に、指定した場合、既定の値を指定することによって、戻り値を修復できます。
マークアップ拡張機能の実装は、あなたが、比較的簡単に達成することができる実用的な例ですが、単純です。 この仕組みには、多くの機能があります。そして、見ての通り、ユーザー定義した動作の作成は、非常に簡単です。
このマークアップ拡張機能の動作の例については、WpfLocalizationResxプロジェクトとLocalizationInfo.xamlドキュメントを見てください。 それは、地域設定のために、StaticExtensionとResExtensionの両方を使用します。
ユーザー定義したマークアップ拡張機能の利点と欠点は、静的な結合といくつかの類似点を持っています。 あなたは、更に、結合式を処理しています。そして、このように、あなたは、依存関係プロパティに結合することだけができます。 更に、あなたが、また、静的な結合とマークアップ拡張機能を組合せて使用できることに注意して下さい。 あなたが、常に、Resx文字列リソースと結合している場合、続いて、あなたが、文字列ではない値に結合する必要があるとき、 あなたはマークアップ拡張機能を使用することができ、x:Staticを使用することは、 多くの場合、最も簡単であり、そして、最も効果的な選択子を除外します。
Resxリソースのどちらの結合方法でも、あなたに最大限の柔軟性とコントロールとプロパティへのマッピング・リソースの最初の処理がより複雑な、 結合処理の制御を提供します。
StaticExtensionと比較した、ユーザー定義したマークアップ拡張機能の長所は以下のとおりです。:
静的な結合より柔軟性がある
厳格に型指定されたリソースか、未加工のResourceManagerのどちらかを使用します。
あなたは、厳密に型指定された静的なリソースへの結合を選択することができます。 あるいは、ユーザー定義したResourceManagerインスタンスを使用して、あなたのマークアップ拡張機能が、インスタンスを生成します。
TypeConverterのサポートは、複雑な型の文字列表現を可能にします。
ユーザー定義したマークアップ拡張機能の型コンバータを、内部的に適用することによって、保証することができます。 それは、あなたが、同じ文字列の値を使用して、簡単に、文字列ではないプロパティに結合することができます。 あなたは、XAMLマークアップの属性の中で、すでに使用しています。
ユーザー定義したResourceManagerやリソースの記憶ができます。
あなたに、あなたが、ユーザー定義したResourceManagerを使用したり、さらに、直接、XMLやデータベースからリソースを読み込んで、 完全に、ResourceManagerを迂回する完全な別々のリソースの記憶を作成することができるので、 マークアップ拡張機能は、リソースがどのように読み込まれるかについて、完全な自由を与えます。
デザイナーでの、リソースの読込失敗のための対応
リソースの読込失敗は、設計時の経験と同じように、実行時に、アプリケーションを壊すことができます。 これは、多くの場合、リソースが、Visual StudioとBlendデザイナーによって見つからない、サテライト・アセンブリの状況で、特に当てはまります。 たとえ、リソースが直接アクセス可能でないとしても、既定の値は、デザイナーが、常に動作することを確実にするために役に立ちます。
その場でカルチャを変更する
マークアップ拡張機能は、それらが、結合している対象の更新を強制する機能をサポートしています。 それで、あなたが、カルチャの変更を検出することができる場合、値を更新することができます。 それがドキュメントを再ロードすることなく、結合されます。この話題は、この白書の後の方で説明します。
短所は以下の通りです。:
カスタム設定が必要
ユーザー定義したマークアップ拡張機能の名前空間は、すべてのページに登録する必要があります。 そして、おそらく、LocalizationSettings.Initialize()に類似したアプリケーションの起動で、いくつかのグローバル構成を必要とします。
Blendデザイナーの問題
厳格なセキュリティー環境そして、Blendが、リソース・アセンブリを解決する方法のために、Blendデザイナーで表示される、ライブリソースを見るのは問題があります。 既定の値は、この問題を軽減することができ、そして、Blendにおいて、設定する場合、あなたは既定の値を見ることができます。
標準的でない解決法
本来、ユーザー定義した拡張機能は、組込みの解決法でありません。 これは、ローカライザが、外部アセンブリをインストールする必要があることを表しています。そして、マークアップ拡張機能を使用するために、ユーザー定義した構文を使用する必要があります。