Control のベースクラスを作る。

コントロールを作成するとき UserControl を直接継承するのではなく、間に一枚噛ますことが多いと思います。以下のような感じです。

namespace MyApp
{
  public class ControlBase : UserControl
  {
  }
}

で、この ControlBase クラスを継承してコントロールを作ります。

namespace MyApp
{
  public class MyControl : ControlBase
  {
  }
}

XAML は純粋に考えると以下のような感じ。

<local:ControlBase x:Class="MyApp.MyControl"
  xmlns="http://schemas.microsoft.com/client/2007" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:local="clr-namespace:MyApp"
  Width="400" Height="300">
  <Grid x:Name="LayoutRoot" Background="White">

  </Grid>
</local:ControlBase>

まぁ、先に「純粋に考えると・・・」なんて書き方してるのでお分かりだと思いますが、これ、動きません。

実行すると「AG_E_UNKNOWN_ERROR」って怒られてしまいます。そうですか、わかりませんせんか。僕もわかりません。

動くようにするためには以下のようにアセンブリに XmlnsDefinitionAttribute を設定します。

using System.Windows.Markup;

[assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007","MyApp")]

で、 xaml の宣言の部分でネームスペースを外してあげます。

<ControlBase x:Class="MyApp.MyControl"
  xmlns="http://schemas.microsoft.com/client/2007" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  Width="400" Height="300">
  <Grid x:Name="LayoutRoot" Background="White">

  </Grid>
</ControlBase>

これで動きます。



XmlnsDefinitionAttribute ですが、ドキュメントを見てみると、どうやら指定された XML のネームスペースに、指定された .NET の namespace の探索を追加するらしいです。

まぁ、確かに。そういう動きですね。

でもね、最初のネームスペースを明示的に指定するのも間違ってないと思うのですよ。 XML 的には。 XAML 的に間違ってるのか??ちょっと調べてみなきゃです。

あと、先日書いた XamlReader でこの MyControl を読み込んだ時の挙動も若干気になります。


※Beta 2 で挙動が変わりました。詳しくはこちら:Beta 2 で挙動が変わったところ。その1