UserControlを2つ以上配置するとエラーになる

Silverlight 3にはElement-to-ElementバインディングというUI要素間のプロパティを相互にバインドできる機能がある。この機能を利用すれば、例えばスライダーのつまみを移動した場合に、テキストブロックにその値をバインディングして自動的に表示させるということがプログラミング無しで可能になる。

この便利な機能を早速試してみようと思い、UserControlにItemというプロパティを追加して、Expression Blendを開き、UserControlに配置されているTextBoxのTextプロパティからItemプロパティをElement-to-Elementバインディングの対象として参照させてみた。そのUserControlをメインのコントロールに貼り付けて実行してみると、見事にItemプロパティの内容がTextBoxに表示された。

これは便利な機能だと調子に乗って、今度はStackPanelの中に先ほど作成したUserControlを複数個挿入されるようにして実行してみた。
すると次のような例外が発生した。

「ArgumentException: 値が期待される範囲にありません。」

例外が発生した箇所を見てみると、StackPanelにUserControlを追加する行を指している。同行にブレークポイントを追加して再実行してみると、どうやら1回目は追加に成功しているが、2回目の追加で例外が発生するらしい。Silverlightにありがちな描画タイミングの問題が発生しているのかとも思い、ボタンを作ってそれを押すと1個ずつUserControlがStackPanelに挿入されるようにして実験してみた。すると、1個目は挿入されるが、2個目はやはり同じ例外が発生してしまう。

試しにTextBoxに設定したItemプロパティへのバインディングを解除して実行してみた。そうしても結果は同じく2回目の追加でエラーとなる。

こうなるといよいよ追い詰められるわけだが、中身を何も変更していない素のUserControlをStackPanelに追加してみた。すると、当たり前のことだが正常に挿入される。
そこで、空のUserControlにやはりItemプロパティを記述し、TextBoxを貼り付けてElement-to-Elementバインディングを設定してみた。そして実行すると、やはり例外が発生する。

段々訳が分からなくなってきたが、Blendで編集されたXAMLをもう一度よく確認してみると、何やら思いがけないコードが挿入されていた。それはUserControlのx:Nameアトリビュートだ。もともとUserControlには何も名前を設定していないのでx:Nameアトリビュートは付いていなかったのだが、Element-to-Elementバインディングの設定をしたときに、Blendによって自動的に付加されたようだ。

確かによく考えてみると、Element-to-Elementの設定では要素の名前を指定している。そのため、何も名前が付けられていないコントロールにはElement-to-Elementバインディングの設定ができない。従って、Blendはご親切にもコントロールに名前が付いていない場合は、コントロールと同名の名前を勝手に付けて、それを要素の名前として設定しているのだ。

このUserControlに勝手に付けられた名前がなぜ問題になるのかといえば、BlendのXAMLエディターで確認すると良く分かる。そこにはUserControlのx:Nameアトリビュートの箇所に、UserControlを同じXAML内に配置した場合に、名前が競合する問題が発生する可能性があるということが表記されていた。

結果的には同じXAML内に2つ以上配置するUserControlには、直接Element-to-Elementバインディングの設定をすることはできないということである。