Standard Controls - ComboBox

 ユーザに複数の選択肢の中からひとつを選択させるためのコントロールです。

ページ内リンク

選択項目リストの指定方法

 ComboBox コントロールにリストを指定する方法は何通りかありますが、 主に次の 2 通りとなります。

  • XAML から直接指定する
  • IEnumerable なオブジェクトをデータバインドする

選択項目名が恒久的に固定で、ある ComboBox コントロールでのみ使用するリストである場合は、 XAML から直接指定することがあります。 直接指定するときは次のように記述します。

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="150" Width="250">
    <StackPanel>
        <ComboBox>
            <ComboBoxItem>指定しない</ComboBoxItem>
            <ComboBoxItem>りんご</ComboBoxItem>
            <ComboBoxItem>みかん</ComboBoxItem>
            <ComboBoxItem>いちご</ComboBoxItem>
        </ComboBox>
    </StackPanel>
</Window>
Code 1 : ComboBox コントロールにリストを直接指定する
Fig.1 : ComboBox コントロールで選択できる

 ViewModel の持つ IEnumerable な公開プロパティとデータバインドすることでも 選択項目リストを指定することができます。 次の例では string 配列の Vegetables プロパティとデータバインドしています。

<Window x:Class="WpfApplication2.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainView" Height="150" Width="250">
    <StackPanel>
        <ComboBox ItemsSource="{Binding Vegetables}" />
    </StackPanel>
</Window>
Code 2 : ItemsSource プロパティにデータバインドする (View 側のコード)
namespace WpfApplication2.ViewModels
{
    public class MainViewModel
    {
        private string[] vegetables = new string[]
        {
            "嫌いだから指定しない",
            "にんじん",
            "ピーマン",
            "グリーンピース",
        };

        public string[] Vegetables
        {
            get { return vegetables; }
        }
    }
}
Code 3 : ItemsSource プロパティにデータバインドする (ViewModel 側のコード)
Fig.2 : ViewModel 側のリストがデータバインドされている

 ところで、どちらの結果もアプリケーション直後は何も選択されていない状態となっています。 これは ComboBox コントロールの SelectedIndex プロパティが既定値の -1 になっているからです。 一般的には初期値として 0 を与えることで、リストの先頭項目が選択された状態にしておきます。

<ComboBox ItemsSource="{Binding Vegetables}" SelectedIndex="0" />
Code 4 : Code 2 で SelectedIndex に 0 を指定した場合
Fig.3 : 始めからリストの先頭が選択された状態で起動する

 上記の例では string 配列をリストにしましたが、 int 型のような数値の配列も同様にリストにすることができます。

クラスを選択項目リストにする方法

 上記の例では string 型や数値の型をリストにしましたが、 クラスの配列をリストにすることもできます。 サンプルクラスとして次のような Person クラスを定義します。

namespace WpfApplication2.Models
{
    public class Person
    {
        /// <summary>
        /// 名前を取得または設定します。
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 年齢を取得または設定します。
        /// </summary>
        public int Age { get; set; }
    }
}
Code 5 : Name プロパティと Age プロパティを持つ Person クラス
このクラスをリストとして持つ ViewModel を次のように記述します。
namespace WpfApplication2.ViewModels
{
    using System.Collections;
    using System.Linq;
    using WpfApplication2.Models;
    using YKToolkit.Bindings;

    public class MainViewModel : NotificationObject
    {
        private IEnumerable persons;
        public IEnumerable Persons
        {
            get { return persons ?? (persons = Enumerable.Range(0, 5).Select(i => new Person { Name = "田中" + i, Age = i })); }
            set { SetProperty(ref persons, value); }
        }
    }
}
Code 6 : Person クラスをリストとして持つ ViewModel
これを表示する View 側は、ItemsSorce プロパティに Persons プロパティをデータバインドするように記述します。
<Window x:Class="WpfApplication2.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainView" Height="150" Width="250">
    <StackPanel>
        <ComboBox ItemsSource="{Binding Persons}" SelectedIndex="0" />
    </StackPanel>
</Window>
Code 7 : ComboBox コントロールに Persons プロパティをデータバインドする
この結果、ComboBox コントロールは次のような表示になります。
Fig.4 : Persons プロパティがデータバインドされた ComboBox コントロール
確かに ViewModel 側で 5 人分の Person クラスを生成しましたが、 これではどれが誰だかわかりません。 というのも、ComboBox コントロールの ItemsSource プロパティには Person クラスのリストが与えられたため、 個々のアイテムは Person クラスとなります。 特に何も指定しない限り、ComboBox のアイテムは与えられたアイテムを string として表示しようとします。 したがって、Person クラスの ToString() メソッドを通した文字列が ComboBox に表示されることになり、上図のようになってしまいます。 これではリストとして役に立たないため、 ComboBox にどう表示すればいいのか指示を与えます。 表示方法を指定するには DisplayMemberPath プロパティに 表示させるプロパティ名を指定します。 ここでは名前を表示させたいので、 Person クラスの Name プロパティを指定するため、 "Name" と指定します。
<Window x:Class="WpfApplication2.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainView" Height="150" Width="250">
    <StackPanel>
        <ComboBox ItemsSource="{Binding Persons}" SelectedIndex="0" DisplayMemberPath="Name" />
    </StackPanel>
</Window>
Code 8 : DisplayMemberPath プロパティによる表示プロパティの指定
Fig.5 : Person クラスの Name プロパティが表示として使われている
ここでは割愛しますが、ComboBox コントロールは ItemsControl コントロールから派生したコントロールなので、 ItemTemplate プロパティ等を使った表示方法の指定もできます。 このことについては ItemsControl コントロールの説明を参照して下さい。

選択された項目について

 ComboBox コントロールで選択された項目を拾うには、SelectedIndex、SelectedItem、SelectedValue というプロパティが使用できます。 Fig.5 のような場合、選択された人物はわかりますが、 その人の年齢を表示する場合は選択されたアイテムを把握する必要があります。 ここでは SelectedItem プロパティを使った例を示します。

<Window x:Class="WpfApplication2.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainView" Height="150" Width="250">
    <StackPanel>
        <ComboBox ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}" DisplayMemberPath="Name" />
        <TextBlock Text="{Binding SelectedPerson.Age}" />
    </StackPanel>
</Window>
Code 9 : SelectedItem プロパティにデータバインドを指定する
上のコードでは、SelectedIndex プロパティの代わりに SelectedItem プロパティを追加し、 ComboBox コントロールの下に TextBlock コントロールを追加しています。 TextBlock コントロールには、SelectedItem プロパティにデータバインドした SelectedPerson という ViewModel のプロパティを用いて、 その Age プロパティを参照するように指定しています。

 ViewModel 側のコードは次のようになります。

namespace WpfApplication2.ViewModels
{
    using System.Collections;
    using System.Linq;
    using WpfApplication2.Models;
    using YKToolkit.Bindings;

    public class MainViewModel : NotificationObject
    {
        private IEnumerable persons;
        public IEnumerable Persons
        {
            get { return persons ?? (persons = Enumerable.Range(0, 5).Select(i => new Person { Name = "田中" + i, Age = i })); }
            set { SetProperty(ref persons, value); }
        }

        private Person selectedPerson;
        public Person SelectedPerson
        {
            get { return selectedPerson; }
            set { SetProperty(ref selectedPerson, value); }
        }
    }
}
Code 10 : SelectedItem プロパティにデータバインドされるプロパティを追加した ViewModel
Fig.6 : 選択された人物の年齢が表示されるようになった

Designed by CSS.Design Sample