XAML: 同じ ItemsSource を持つ複数のコントロールの効率的な定義の仕方、あるいは ItemsSource を StaticResource で別定義する方法
例えば同じ要素軍を選択肢として提示する複数のコンボボックスを配置したいとしよう。以下のコード例は何れも <Window>
の内部に定義している。
<!--ダサいがシンプルで間違いは無い実装。しかしダサい。--> <ComboBox Name="CB1"> <ComboBoxItem Content="選択肢1"/> <ComboBoxItem Content="選択肢2"/> <ComboBoxItem Content="選択肢3"/> </ComboBox> <ComboBox Name="CB2"> <ComboBoxItem Content="選択肢1"/> <ComboBoxItem Content="選択肢2"/> <ComboBoxItem Content="選択肢3"/> </ComboBox>
↑ダサい。
そこで XAML 初心者のわたしは先ず次のようにしてみた。
<!--これは期待動作しません。--> <ComboBox Name="CB1"> <ComboBoxItem Content="選択肢1"/> <ComboBoxItem Content="選択肢2"/> <ComboBoxItem Content="選択肢3"/> </ComboBox> <ComboBox Name="CB2" ItemsSource="{Binding ItemsSource,ElementName=CB1"/>
↑これはコンパイルはできるが実行してもCB2の選択肢が何も出てこない。
<!--これも期待動作しません。--> <ComboBox Name="CB1"> <ComboBoxItem Content="選択肢1"/> <ComboBoxItem Content="選択肢2"/> <ComboBoxItem Content="選択肢3"/> </ComboBox> <ComboBox Name="CB2" ItemsSource="{Binding Items,ElementName=CB1"/>
↑これはコンパイルはできるし、実行するとCB2にも選択肢がでるのだが、CB2でドロップダウンされた選択肢を選択してもCB1の値へ適用されるという怪奇現象を引き起こした。
<Window xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
↑と x
が使用可能として、
<!--期待動作する例--> <Window.Resources> <x:Array Type="ComboBoxItem" x:Key="CBItems"> <ComboBoxItem Content="選択肢1"/> <ComboBoxItem Content="選択肢2"/> <ComboBoxItem Content="選択肢3"/> </x:Array> </Window.Resources> <ComboBox Name="CB1" ItemsSource="{StaticResource CBItems}"/> <ComboBox Name="CB2" ItemsSource="{StaticResource CBItems}"/>
↑期待動作する😃
ちなみに、 <ComboBoxItem Content="hoge" Tag="fuga"/>
など Content
属性の他にも設定したい何かしらがある場合はさておき、そうではないただの文字列のリストの StaticResource
を定義して使えればよい場合には、
<Window.Resources> <x:Array xmlns:s="clr-namespace:System;assembly=mscorlib" Type="s:String" x:Key="StringItems"> <s:String>梅干し</s:String> <s:String>生姜</s:String> <s:String>小葱</s:String> </x:Array> </Window.Resources>
↑など定義し、これも ComboBox
の ItemsSource
の StaticRerouce
としてぶちこめる。この場合には ComboBox
ではなく ListBox
にも放り込めるようになる。
なお、 XAML
で完結する必要が無ければ XAML
側では ItemsSource{Binding MyDataContextProperty}
としておいてコードで Window
の DataContext
に IEnumerable< string >
な MyDataContextProperty
を持つオブジェクトを放り込めばよい。この方法は ItemsSource
に列挙する選択肢が実行中に変化する場合にはより適切だろう。