読者です 読者をやめる 読者になる 読者になる

XAML で定義して XamlReader で読み込んでインスタンス化する

Child オブジェクトを複数持つ Parent オブジェクトを XAML で定義して、 XamlReader で読み込んでインスタンス化する。クラス構成は以下。

namespace SilverlightApplication1
{
  [ContentProperty("Children")]
  public class Parent
  {
    public Parent()
    {
      this.Children = new List<IChild>();
    }

    public List<IChild> Children { get; private set; }

    public string Name { get; set; }
  }

  public interface IChild
  {
  }

  public class Child : IChild
  {
    public Child()
    {
    }

    public string Name { get; set; }
  }
}

読み込んでみる。

XamlReader.Load(@"<Parent
  xmlns='clr-namespace:SilverlightApplication1'
  Name='foo'>
  <Child Name='bar' />
  <Child Name='baz' />
</Parent>");

例外が発生した。AG_E_PARSER_NAMESPACE_NOT_SUPPORTED だと。
どうやら、ルート要素にデフォルトのネームスペースを書かないとだめらしい。
http://msdn.microsoft.com/en-us/library/cc190359(VS.95).aspx

むぅ。なんか気持ち悪い気もしないでもないが、このネームスペースがあるってことで XMLXAML であることを確定してるのか・・・。

XamlReader.Load(@"<local:Parent
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:local='clr-namespace:SilverlightApplication1'
  Name='foo'>
  <local:Child Name='bar' />
  <local:Child Name='baz' />
</local:Parent>");

なんか、結局全部 local のネームスペースやから変な感じ。
でも、例外が発生した。

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

だってさ。なんやこれ??

local のネームスペースの定義をアセンブリまで含めて書いてみることにする。

XamlReader.Load(@"<local:Parent
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:local='clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1'
  Name='foo'>
  <local:Child Name='bar' />
  <local:Child Name='baz' />
</local:Parent>");

おっ、例外が変わった。

Parent does not support Child as content

だとさ。ってことはやっぱりアセンブリまでふくめて定義する必要があるらしい。

で、Child はコンテントに設定できひんわ!って怒られてるっぽい。だめなことはないと思うんやけど・・・。

Parent のクラスの属性に ContentProperty を指定して、 XAML で指定した時の子要素を自動的に Children プロパティに当て込むようにしてたけど、それをやめて、 XAML にちゃんと Children プロパティを指定するようにしてみる。

XamlReader.Load(@"<local:Parent
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:local='clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1'
  Name='foo'>
  <local:Parent.Children>
    <local:Child Name='bar' />
    <local:Child Name='baz' />
  </local:Parent.Children>
</local:Parent>");

おっ、いけた。通りました。が、 Name の値が設定されてない。。

xaml の属性をクラス名も含めた形に変更してみる。

XamlReader.Load(@"<local:Parent
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:local='clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1'
  Parent.Name='foo'>
  <local:Parent.Children>
    <local:Child Child.Name='bar' />
    <local:Child Child.Name='baz' />
  </local:Parent.Children>
</local:Parent>");

AG_E_RUNTIME_MANAGED_UNKNOWN_ERROR

むぅ。中では DependencyProperty つかって DependencyObject やと思って SetValue を呼び出してるのか?なんかそんな気がするだけやけど。

で、ふと思った。 "Name" ってのがあやしい気がする。通常の画面を定義する場合、 x:Name 属性で指定したのが、 Name プロパティに当て込まれて、普通に Name って指定した場合は、無視されるんです。なので、今回も無視されてる??

Name プロパティを FirstName プロパティに変えて再挑戦。

public string FirstName { get; set; }
XamlReader.Load(@"<local:Parent
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:local='clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1'
  FirstName='foo'>
  <local:Parent.Children>
    <local:Child FirstName='bar' />
    <local:Child FirstName='baz' />
  </local:Parent.Children>
</local:Parent>");

いけてしまった。。。

ためしに x ネームスペースを追加して、 x:Name で指定するようにしてみる。もちろん FirstName プロパティからプロパティ名を Name に戻す。

public string Name { get; set; }
XamlReader.Load(@"<local:Parent
  xmlns='http://schemas.microsoft.com/client/2007'
  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  xmlns:local='clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1'
  x:Name='foo'>
  <local:Parent.Children>
    <local:Child x:Name='bar' />
    <local:Child x:Name='baz' />
  </local:Parent.Children>
</local:Parent>");

むぅ、いけなかった。それが正しいといえば正しいけど、じゃ、どうするのよ。


仕方がないので、 Name という名前のプロパティは使わないようにってことで。しかし、なんかいまいち・・・。