2013-12-11 18 views
16

XAML(またはBAML)を読み込んでからルートオブジェクト(ウィンドウなど)を受け取るまでに内部的にはどうなりますか?XAMLはどのように解釈され、実行時に実行されますか?

私の心の中で最初にポップアップするのは、Reflectonがオブジェクトの作成、プロパティの設定などに使用されることです。しかし、多分私は間違っていますか?

誰かがXAML/BAMLを実行時に解析して実行する方法や説明付きの良い記事へのリンクを与える方法を説明する人はいますか?

<Button Margin="10">OK</Button> 

ので、パーサはそのMarginプロパティがに設定されなければならないことを、Buttonオブジェクトを作成する必要があることを見ている:

はのは、簡単な例を説明しましょう、もう少し明確に私の質問を作成するには10の内容を "OK"に設定する必要があります。それはどうですか? Reflection(とTypeConvertersなど)を使用することによって?

答えて

25

.xaml.csファイルには、コンパイル済みのXAMLファイルをサポートするクラスがpartialクラスとしてマークされていることがあります。 XAMLビルドタスクは、IComponentConnector.InitializeComponent()メソッドの実装を含む別の部分クラスセクションを含む2番目の.csファイルを生成します。これはコードの背後にあるデフォルトのコンストラクタによって呼び出されます。このメソッドは、XAMLソースから新しいオブジェクトを作成するのではなく、新しく作成されたオブジェクトを「修正する」ために、基本的にはXAML(現時点ではBAML形式です)を使用して実行されます。オブジェクトをロードまたは解析するためにXamlReaderを使用しました。

したがって、コンパイル済みの新しいXAMLオブジェクト(たとえば、UserControl)をインスタンス化すると、コンストラクタ内のInitializeComponent()への呼び出しに先行するコードが実行されます。次に、XAMLファイルに設定されているすべてのプロパティとイベントハンドラは、InitializeComponent()の呼び出し中に処理されます。その後、コンストラクタが再開されます。これは、XAMLファイルが処理される前または後に特定のプロパティが設定されるようにするために便利です。

XAMLがどのように解析されるかは、サービスによって順番にプロパティ割り当て、オブジェクト宣言などを表すXAMLノードのストリームとして読み取られます(System.Xaml)。このノードストリームは、BAMLストリーム、XML文書(緩い.xamlファイルなど)、別のオブジェクトインスタンスなどから構築された共通オブジェクトモデルに基づいています.BAMLはXMLベースの形式よりもコンパクトです一般に解析する方が高速です。


補遺:あなたは追加の例では、あなたはパーサがButtonオブジェクトを作成する必要があることを認識し、Marginセット方法を尋ねます。短い答えは:それは依存しています。具体的には、XAMLストリームの読み込みに使用されるスキーマコンテキストに依存します。

XAMLパーサーは、少なくとも2つの実装があり、そのうちの独自のタイプのシステムを使用する:

  1. 反射及びSystem.ComponentModelに基づく標準CLR型システムは、
  2. 依存関係のプロパティとルーティングされたイベントを特別にサポートすることで#1を拡張するWPFタイプのシステム。

これは、XAML言語仕様の私の記憶に基づいて、おおよそ何が起こる、次のとおりです。

  1. をXAMLパーサーは、(標準WPF名前空間のマッピングのために)これ、ButtonタイプにStartObjectノードに遭遇System.Windows.Controls.Buttonに解決されます。これはパーサーに、Buttonオブジェクトのインスタンスを作成する必要があることを伝えます。これは、リフレクションによってデフォルトのコンストラクタを呼び出すことによって行われます。
  2. ストリームの次のノードはStartMemberノードであり、メンバー名はMarginです。 WPFスキーマコンテキストの型モデルは、これをMargin依存プロパティに解決します。
  3. Valueノードが次に来ます。これは、パーサーに"10"(文字列)の値を設定するように指示します。パーサは、プロパティタイプThicknessが文字列値と互換性がないことを確認します。文字列の変換に使用できるMarginプロパティに[ValueSerializer]属性が存在するかどうかを調べるために型システムを調べます。そのような属性は存在しません。プロパティーで[TypeConverter]属性をチェックします。もう一度、それは何も見つけません。これは、タイプ自体の[TypeConverter]属性を検索し、ThicknessConverterを使用して文字列値をThicknessに変換するよう指示します。そうです。 Marginは依存関係プロパティであるため、SetValue() APIを使用してプロパティ値を設定します。 CLRプロパティの場合は、リフレクションまたはPropertyDescriptorを使用します。
  4. EndMemberノードは、プロパティの割り当てを終了するようにパーサに指示します。
  5. パーサーは"OK"という内容のValueノードを検出します。パーサーは複合オブジェクトを構成していることを知っているので、コンテンツはオブジェクト全体を表すことができません。 Buttonとそのスーパータイプの[ContentProperty]属性を探します。 ContentControlにある値を見つけます。これは、Contentプロパティ(対応する依存関係プロパティに解決されます)を設定するために値を使用する必要があることを示します。 Contentobjectであるため、stringの値が直接割り当てられます(再びSetValue()を使用)。
  6. 次のノードはEndObjectです。これは、パーサーにButtonオブジェクトの処理を終了したことを通知します。

私は事を単純化するために "パーサー"という用語を使用しました。実際には、解析の段階でこのようなことは起こりません(「解析」段階が存在する場合でも)。 「解析」段階と考えることができるのは、XAMLノードのストリームの構築だけです。宣言されたオブジェクトの作成および/または作成は、そのストリームをXamlObjectWriterに入力することによって実際に発生します。XamlWriterの実装は、(XMLドキュメントまたはBAMLストリームではなく)オブジェクトにXAMLノードを書き込みます。高レベルでは、起こるのは2つだけです:

  1. XamlReader何かがXAMLノードのストリームに変換されます。
  2. XamlWriterは、XAMLノードのストリームを何かに変換します。 compled XAMLリソースの場合

、コンパイル時ビルドタスクパイプBamlWriterXamlXmlReaderの出力は、XAMLを「コンパイル」します。実行時にBamlReaderの入力はXamlObjectWriterにパイプされ、ルートオブジェクトを作成または修正します。

これを理解したら、UIを構築するための単なる言語ではなく、強力なシリアライズと永続化形式としてXAMLを認識することができます。

+0

マイク、ありがとうございました。あなたの補遺は私が必要としたものです。そのため、WPFエンジンでオブジェクトツリーを構築するには、Buttonオブジェクトを作成し、使用するTypeConverterを見つけ出し、TypeConverterを構築し、Marginが依存関係プロパティであることなどを確認してください。 – WpfNewbie

+1

はい、XAMLタイプのシステムでは、多くのことが反映されています。 –

+0

偉大な答え! – nawfal

関連する問題