ListBoxの選択した要素の内容を他のコントールに表示する場合、WPFでは、xaml内でデータ結合を使用することで、C#コードを記述せずに実現することができます。
UI内部の動きをxamlコード内で完結することで、分離コードに記述するC#コードの量が減り、C#コードが見やすくなります。その結果、C#コードを修正することなく、xaml側の変更だけで、UIを変更できます。一方、その分、xamlコードが増えるので、どちらが良いのかは、一概に判断できません。
ListBoxItemで追加した項目を扱う
xamlコード内で、ListBox内に項目をListBoxItem要素として追加する場合、追加された項目は、ListBoxItemクラスです。そのため、ListBoxに、String型の要素を追加した場合とは扱いが異なります。
ListBox内で項目を選択したとき、上のTextBlockには、ListBoxのSelectItemが、下のTextBlockには、ListBoxのSelectItem.Contentが表示されます。
MainWindow.xaml
<Window x:Class="ListBoxBinding01.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="300">
<DockPanel>
<TextBlock DockPanel.Dock="Top" Name="ListItem" Height="30" Padding="5,0,0,0"
Text="{Binding ElementName=Listbox01, Path=SelectedItem}"/>
<TextBlock DockPanel.Dock="Top" Name="ListItemName" Height="30" Padding="5,0,0,0"
Text="{Binding ElementName=Listbox01, Path=SelectedItem.Content}"/>
<ListBox DockPanel.Dock="Bottom" Name="Listbox01" SelectionMode="Single">
<ListBoxItem Content="みかん"/>
<ListBoxItem Content="りんご"/>
<ListBoxItem>ばなな</ListBoxItem>
</ListBox>
</DockPanel>
</Window>
このコードは、xamlコードで書かれています。xamlコードは、xmlと呼ばれる記述方法に従って、UIを定義する方法です。
Windowタグの中に、DockPanelタグ、その中に、TextBlockタグとListBoxタグが入っています。
これらのそれぞれは、UIを示しており、Windowsタグが、キャプション(この例では、MainWindow)を含む、ウィンドウを表しています。続く、DockPanelは、レイアウト・パネルやレイアウト・コンテナと呼ばれ、この中に入れ子にするコントロールの配置方法を決定するパネルです。
この例では、DockPanelの中に、TextBlockが2つ、ListBoxが1つ入っています。この状態を「入れ子」や「ネスト」と表現します。DockPanelは、入れ子になった要素を指定した端部(DockPanel.Dock属性で、指定する既定はTop)から、順番に並べていき、最後の要素に残った領域を割り当てます。そのため、この例では、何も指定していなのに、ListBoxが、TextBlockより大きな領域が割り当てられています。
ListBoxでは、 DockPanel.Dock属性、Name属性、SelectionMode属性が指定されています。
DockPanel.Dock属性は、先程説明したDockPanelの配置する端部の位置を指定しています。
Name属性は、コントールを識別するために名前です。このコントロールを対象に何か行うとき、Name属性で、指定します。
SelectionMode属性は、ListBoxの選択モードを指定します。この例では、Singleを指定し、項目を1つしか選択出来ないようにしています。
ListBox内で、項目を指定する際は、ListBoxItemコントロールを使用します。内容は、Content属性に指定する方法と
<ListBoxItem Content="みかん"/>
開始タグと終了タグの間に記述する方法があります。
<ListBoxItem>ばなな</ListBoxItem>
TextBlockで、DockPanel.Dock属性、Name属性、Height属性、Padding属性、Text属性を指定しています。
Padding属性は、コントロール内に記述する位置を指定します。TextBlockでは、文字を記述する位置です。何も指定しない場合、左に文字が寄りすぎて、見えにくかったので、指定しています。
Text属性は、TextBlockで表示する文字を指定します。通常、文字列で指定します。今回の例は、データ結合の例なので、データ結合で指定しています。
Text="{Binding ElementName=Listbox01, Path=SelectedItem}"
ElementNameは、データ結合するコントールのName属性を指定します。
Pathは、データ結合するデータを指定します。
Text属性は、String型のデータを要求するので、「SelectItem」のようにObject型を指定すると、自動で型変換が実行されます。今回の場合は、おそらく、ToStringメソッド。そのため、ListBoxの項目「みかん」を指定するとTextBlockには、ListBoxの項目として、表示されている値とは異なる値、「System.Windows.Controls.ListBoxItem:みかん」と表示されます。
「みかん」と表示するには、Passに、「SelectedItem」ではなく、「SelectedItem.Content」と指定します。
Text="{Binding ElementName=Listbox01, Path=SelectedItem.Content}"
C#コードからListBoxにString型の要素を追加する
C#コードからListBoxに項目を追加するコードを探すと、String型の要素を追加する例が見つかります。
しかし、xamlコード内で、ListBox内に項目をListBoxItem要素を追加し、更に、C#コードで、String型の要素を追加すると、ListBox内の要素を表示する際に問題が生じます。
xamlコードはそのままで、分離コードを以下のように変更します。
MainWindow.xaml.cs
using System.Windows;
namespace ListBoxBinding01
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// リストの初期値を入力
SetInitialListItems();
}
private void SetInitialListItems()
{
Listbox01.Items.Add("もも");
Listbox01.Items.Add("いちご");
Listbox01.Items.Add("ぶどう");
}
}
}
SelectedItem | SelectedItem.Content |
---|---|
System.Windows.Controls.ListBoxItem: みかん | みかん |
System.Windows.Controls.ListBoxItem: りんご | りんご |
System.Windows.Controls.ListBoxItem: ばなな | ばなな |
もも | |
いちご | |
ぶどう |
ListBoxに表示される内容を表示したい場合、「SelectedItem」、「SelectedItem.Content」で表示すると、xamlコード内で、ListBox内に、ListBoxItem要素で追加した項目と、C#コードで、String型の要素として追加した項目で表示される内容が異なるので、ListBox内の項目に混在させる場合は、注意が必要です。
C#コードからListBoxItem要素を追加する
簡単な解決策は、ListBoxに追加する項目の型を統一することです。
C#コードでも、ListBoxItem要素として、ListBoxを追加することで、ListBox内の要素を表示することが簡単になります。
<Window x:Class="ListBoxDataBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="250" Width="300">
<DockPanel>
<TextBlock DockPanel.Dock="Top" Name="ListItem" Height="30" Padding="5,0,0,0"
Text="{Binding ElementName=Listbox01, Path=SelectedItem}"/>
<TextBlock DockPanel.Dock="Top" Name="ListItemName" Height="30" Padding="5,0,0,0"
Text="{Binding ElementName=Listbox01, Path=SelectedItem.Content}"/>
<ListBox DockPanel.Dock="Bottom" Name="Listbox01" SelectionMode="Single">
<ListBoxItem Content="みかん"/>
<ListBoxItem Content="りんご"/>
<ListBoxItem>ばなな</ListBoxItem>
</ListBox>
</DockPanel>
</Window>
using System.Windows;
using System.Windows.Controls;
namespace ListBoxDataBinding
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// リストの初期値を入力
SetInitialListItems();
}
private void SetInitialListItems()
{
AddListBoxItem("もも");
AddListBoxItem("いちご");
AddListBoxItem("ぶどう");
}
private void AddListBoxItem(string strItem)
{
ListBoxItem myItem = new ListBoxItem();
myItem.Content = strItem;
Listbox01.Items.Add(myItem);
}
}
}
参考資料
- ListBox クラス[msdn](外部サイト)
- リストボックスで選択した項目をデータ結合でテキストボックス表示する(外部サイト)
- WPFサンプル:ListBox(外部サイト)