ViewMakerで生成するWPF/Silverlightコントロール(5)RadioButtonList編

WPF/SilverlightにはRadioButtonListというものはないのですが、ASP.NETではよく利用させてもらっていたので、RadioButtonではなくRadioButtonListとして取り込みました。RadioButton自体はグループの任意の1つを選択するというものなのでSelector的な概念ともマッチしますしね。

RadioButtonListコントロール

RadioButton自体はWPF/Silverlight標準で含まれています。これをListBoxのアイテムとして利用することでRadioButtonListを実現しています。WPFSilverlightはカスタムコントロールを作成しなくてもこのコントロールテンプレート機能を利用することでコントロールのカスタマイズができます。以後で実際のXamlを載せているので興味のある方は見てください。
ViewMakerで指定可能なRadioButtonListの項目はListBox+αの以下になります。

    1. ItemsSource(一覧用のデータソース)
    2. SelectedValuePath(ItemsSourceで選択されたデータの値を示すプロパティのパス)
    3. DisplayMemberPath(ItemsSourceの各アイテムの表示に利用するプロパティのパス)
    4. ItemWidth(アイテム幅)
    5. Orientation(アイテムの配置方向)
    6. SelectionChangedCommand(選択データ変更時に実行するコマンド)

WPFサンプルイメージとXAMLコード

          <ListBox Name="RadioButtonList1" ItemsSource="{Binding Path=ItemSource1,Mode=OneWay}" SelectedItem="{Binding Path=RadioButtonList1, 
		Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}" 
		vg:SelectionChangedBehavior.Command="{Binding Path=SelectionChangedCommand1, Mode=OneWay}" 
		IsTabStop="False" BorderThickness="0" xmlns:vg="clr-namespace:ViewMaker.Core.Wpf;assembly=ViewMaker.Core">
             <ListBox.Resources>
 		<Style TargetType="{x:Type ListBox}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
 		   <Setter Property="ItemsPanel">
 		       <Setter.Value>
 		           <ItemsPanelTemplate>
 		               <StackPanel Orientation="Horizontal" />
 		           </ItemsPanelTemplate>
		       </Setter.Value>
		   </Setter>
		   <Setter Property="ItemContainerStyle">
		       <Setter.Value>
		            <Style TargetType="{x:Type ListBoxItem}">
 		               <Setter Property="Template">
		                    <Setter.Value>
		                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
		                            <RadioButton Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, 
						RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
		                                <ContentPresenter />
 		                           </RadioButton>
		                        </ControlTemplate>
		                    </Setter.Value>
		                </Setter>
		            </Style>
		        </Setter.Value>
		    </Setter>
		 </Style>
	  </ListBox.Resources>
          </ListBox>

          <ListBox Name="RadioButtonList2" ItemsSource="{Binding Path=ItemSource2,Mode=OneWay}" SelectedValue="{Binding Path=RadioButtonList2, 
		Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}" SelectedValuePath="Key" 
		DisplayMemberPath="Value" vg:SelectionChangedBehavior.Command="{Binding Path=SelectionChangedCommand2, Mode=OneWay}" 
		IsTabStop="False" BorderThickness="0" xmlns:vg="clr-namespace:ViewMaker.Core.Wpf;assembly=ViewMaker.Core">
            <ListBox.Resources>
		<Style TargetType="{x:Type ListBox}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
		    <Setter Property="ItemsPanel">
 		       <Setter.Value>
		            <ItemsPanelTemplate>
		                <StackPanel Orientation="Vertical" />
		            </ItemsPanelTemplate>
		       </Setter.Value>
		    </Setter>
		    <Setter Property="ItemContainerStyle">
        		       <Setter.Value>
            		<Style TargetType="{x:Type ListBoxItem}">
 	                 	  <Setter Property="Template">
                       	    <Setter.Value>
                        	      <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            		<RadioButton Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, 
						RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
                                		<ContentPresenter />
                            		</RadioButton>
                        	     </ControlTemplate>
                    	             </Setter.Value>
                	          </Setter>
            	       </Style>
        		    </Setter.Value>
    		  </Setter>
		</Style>
	 </ListBox.Resources>
          </ListBox>

          <ListBox Name="RadioButtonList3" SelectedItem="{Binding Path=RadioButtonList3, Mode=TwoWay, ValidatesOnExceptions=True, 
		ValidatesOnDataErrors=True}" FontSize="14" Foreground="Blue" Background="Azure" IsTabStop="False" BorderThickness="0">
            <ListBoxItem Content="one" />
            <ListBoxItem Content="two" />
            <ListBoxItem Content="three" />
            <ListBox.Resources>
	  <Style TargetType="{x:Type ListBox}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    	    <Setter Property="ItemsPanel">
        	      <Setter.Value>
            	<ItemsPanelTemplate>
                		<StackPanel Orientation="Horizontal" />
            	</ItemsPanelTemplate>
        	      </Setter.Value>
              </Setter>
              <Setter Property="ItemContainerStyle">
                <Setter.Value>
                   <Style TargetType="{x:Type ListBoxItem}">
                      <Setter Property="Template">
                        <Setter.Value>
                          <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <RadioButton Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, 
					RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Width="150">
                                <ContentPresenter />
                            </RadioButton>
                          </ControlTemplate>
                       </Setter.Value>
                     </Setter>
                   </Style>
                </Setter.Value>
              </Setter>
            </Style>
            <Style TargetType="{x:Type RadioButton}">
	   <Setter Property="FontSize" Value="14" />
	   <Setter Property="Foreground" Value="Blue" />
	   <Setter Property="Background" Value="Azure"/>
	 </Style>
	</ListBox.Resources>
         </ListBox>

SilverlightサンプルイメージとXAMLコード

          <ListBox Name="RadioButtonList1" ItemsSource="{Binding Path=ItemSource1,Mode=OneWay}" 
		SelectedItem="{Binding Path=RadioButtonList1, Mode=TwoWay, ValidatesOnExceptions=True, 
		ValidatesOnDataErrors=True}" IsTabStop="False" BorderThickness="0">
            <i:Interaction.Behaviors>
              <vg:SelectionChangedBehavior vg:Command="{Binding Path=SelectionChangedCommand1, Mode=OneWay}" 
		xmlns:vg="clr-namespace:ViewMaker.Core.Silverlight;assembly=SilverlightViewMaker.Core" />
            </i:Interaction.Behaviors>
            <ListBox.ItemsPanel>
              <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
              </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
              <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                  <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                      <Grid Background="Transparent">
                        <RadioButton IsHitTestVisible="False" IsTabStop="False" IsChecked="{TemplateBinding IsSelected}">
                          <ContentPresenter></ContentPresenter>
                        </RadioButton>
                      </Grid>
                    </ControlTemplate>
                  </Setter.Value>
                </Setter>
              </Style>
            </ListBox.ItemContainerStyle>
          </ListBox>

          <ListBox Name="RadioButtonList2" ItemsSource="{Binding Path=ItemSource2,Mode=OneWay}" 
		SelectedValue="{Binding Path=RadioButtonList2, Mode=TwoWay, ValidatesOnExceptions=True, 
		ValidatesOnDataErrors=True}" SelectedValuePath="Key" DisplayMemberPath="Value" IsTabStop="False" BorderThickness="0">
            <i:Interaction.Behaviors>
              <vg:SelectionChangedBehavior vg:Command="{Binding Path=SelectionChangedCommand2, Mode=OneWay}" 
		xmlns:vg="clr-namespace:ViewMaker.Core.Silverlight;assembly=SilverlightViewMaker.Core" />
            </i:Interaction.Behaviors>
            <ListBox.ItemsPanel>
              <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical" />
              </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
              <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                  <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                      <Grid Background="Transparent">
                        <RadioButton IsHitTestVisible="False" IsTabStop="False" IsChecked="{TemplateBinding IsSelected}">
                          <ContentPresenter></ContentPresenter>
                        </RadioButton>
                      </Grid>
                    </ControlTemplate>
                  </Setter.Value>
                </Setter>
              </Style>
            </ListBox.ItemContainerStyle>
          </ListBox>

          <ListBox Name="RadioButtonList3" SelectedItem="{Binding Path=RadioButtonList3, Mode=TwoWay, 
		ValidatesOnExceptions=True, ValidatesOnDataErrors=True}" FontSize="14" Foreground="Blue" 
		Background="Azure" IsTabStop="False" BorderThickness="0">
            <ListBoxItem Content="one" />
            <ListBoxItem Content="two" />
            <ListBoxItem Content="three" />
            <ListBox.ItemsPanel>
              <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
              </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
              <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                  <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                      <Grid Background="Transparent">
                        <RadioButton IsHitTestVisible="False" IsTabStop="False" IsChecked="{TemplateBinding IsSelected}" 
			Width="150" FontSize="14" Foreground="Blue" Background="Azure">
                          <ContentPresenter></ContentPresenter>
                        </RadioButton>
                      </Grid>
                    </ControlTemplate>
                  </Setter.Value>
                </Setter>
              </Style>
            </ListBox.ItemContainerStyle>
          </ListBox>

ViewModelコード

        [View(ViewControlType.StackPanel)]
        [ViewProperty(StackPanelViewControl.Properties.HeaderPosition, LayoutHeaderPosition.Hidden)]
        [ViewLayoutGeneratorProvider("Generate")]
        public class RadioButtonListSample : ViewModel
        {
            [View(ViewControlType.RadioButtonList)]
            [ViewProperty(RadioButtonListViewControl.Properties.ItemsSource, "ItemSource1")]
            [ViewProperty(RadioButtonListViewControl.Properties.Orientation, LayoutOrientation.Horizontal)]
            [ViewProperty(RadioButtonListViewControl.Properties.SelectionChangedCommand, "SelectionChangedCommand1")]
            public string RadioButtonList1 { get; set; }

            [View(ViewControlType.Label)]
            [Display(Name = "Seleced Value")]
            [ViewProperty(LabelViewControl.Properties.HeaderPosition, LayoutHeaderPosition.Left)]
            public string RadioButtonList1Value { get; set; }

            [View(ViewControlType.RadioButtonList)]
            [ViewProperty(RadioButtonListViewControl.Properties.ItemsSource, "ItemSource2")]
            [ViewProperty(RadioButtonListViewControl.Properties.DisplayMemberPath, "Value")]
            [ViewProperty(RadioButtonListViewControl.Properties.SelectedValuePath, "Key")]
            [ViewProperty(RadioButtonListViewControl.Properties.SelectionChangedCommand, "SelectionChangedCommand2")]
            public string RadioButtonList2 { get; set; }

            [View(ViewControlType.Label)]
            [Display(Name = "Seleced Value")]
            [ViewProperty(LabelViewControl.Properties.HeaderPosition, LayoutHeaderPosition.Left)]
            public int RadioButtonList2Value { get; set; }

            [View(ViewControlType.RadioButtonList)]
            [ViewProperty(RadioButtonListViewControl.Properties.FontSize, 14.0)]
            [ViewProperty(RadioButtonListViewControl.Properties.ItemWidth, 150)]
            [ViewProperty(RadioButtonListViewControl.Properties.Foreground, "Blue")]
            [ViewProperty(RadioButtonListViewControl.Properties.Background, "Azure")]
            [ViewProperty(RadioButtonListViewControl.Properties.Orientation, LayoutOrientation.Horizontal)]
            public string RadioButtonList3 { get; set; }

            [Browsable(false)]
            public List<string> ItemSource1
            {
                get { return new List<string>(new string[] { "ONE", "TWO", "THREE" }); }
            }

            [Browsable(false)]
            public Dictionary<int, string> ItemSource2
            {
                get
                {
                    var dict = new Dictionary<int, string>();
                    dict.Add(1, "One");
                    dict.Add(2, "Two");
                    dict.Add(3, "Three");
                    return dict;
                }
            }

            [Browsable(false)]
            public ICommand SelectionChangedCommand1 { get { return CreateCommand(SelectionChanged1); } }
            private void SelectionChanged1(object x)
            {
                var data = (object[])x;
                RadioButtonList1Value = (string)data[0];
                OnPropertyChanged("RadioButtonList1Value");
            }
            [Browsable(false)]
            public ICommand SelectionChangedCommand2 { get { return CreateCommand(SelectionChanged2); } }
            private void SelectionChanged2(object x)
            {
                var data = (object[])x;
                RadioButtonList2Value = ((KeyValuePair<int, string>)data[0]).Key;
                OnPropertyChanged("RadioButtonList2Value");
            }

            public static ViewLayoutItem Generate()
            {
                var svc = ServiceLocator.GetService<IViewLayoutGenerator>();
                var layout = svc.Generate(typeof(RadioButtonListSample), LayoutGenerateFlag.All & ~LayoutGenerateFlag.StaticProvider);

                var items = layout.FindChild("RadioButtonList3").GetControl<RadioButtonListViewControl>().ItemsList;
                items.Add("one");
                items.Add("two");
                items.Add("three");
                return layout;
            }
        }