(2020/09/22追記)
「ジェネリックメソッド」を用いることで、 List<T>
の <T>
に当たる部分を呼び出し元で指定できることが分かりました。リストボックスの中身を取得するメソッドくん②、最終的なコード全体②として記載しました。 @MinoruSanou さん、ありがとうございます。
(2020/09/26追記)
長々と記事を書きましたが、 @TN8001 さんの [こちらのコメント][] に、現状僕が知る中で一番簡単な ListBox.SelectedItem を取得するコードを掲載頂きました。TN8001 さんありがとうございます。
[こちらのコメント]:https://qiita.com/Michio029/items/fd597470cc62cfa79ed7#comment-e4c149eb4e00ada84c49
#背景
以前 こちら でListBox.SelectedItemsの中身を取り出す方法を書きました。しかし ListBox が複数になるとコード量が多く邪魔だったので、中身を取得する専用のメソッドくんを考えました。
#準備
WPFでリストを複数(今回は二つ)作る。
c#でリスト項目をセット
<Window>
<Grid>
<!-- 上下に2分割 -->
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 上半分 -->
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="リストボックス1"/>
<ListBox Grid.Row="1" Name="ExampleList1" Margin="10" SelectionMode="Extended" ScrollViewer.VerticalScrollBarVisibility="Auto">
<!-- SelectionMode="Extended" :ctrl,shift+クリックで複数選択可能 -->
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id, StringFormat=IDは{0} :}"/>
<TextBlock Text="{Binding Name, StringFormat= Nameは{0} :}"/>
<TextBlock Text="{Binding Age, StringFormat= Ageは{0}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="2" Name="Btn1" Content="ボタン1" Margin="50,0,50,0" Click="Btn1_Click"/>
</Grid>
<!-- 下半分 -->
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="リストボックス2" Grid.ColumnSpan="2"/>
<ListBox Grid.Row="1" Name="ExampleList2" Margin="10" SelectionMode="Extended" ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.ColumnSpan="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id, StringFormat=IDは{0} :}"/>
<TextBlock Text="{Binding Name, StringFormat= Nameは{0} :}"/>
<TextBlock Text="{Binding Age, StringFormat= Ageは{0}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="2" Name="Btn2" Content="ボタン2" Margin="50,0,50,0" Click="Btn2_Click" Grid.ColumnSpan="2"/>
</Grid>
</Grid>
</Window>
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
List<ExampleClass> list = new List<ExampleClass>();
public MainWindow()
{
InitializeComponent();
list.Add(new ExampleClass() { Id = 0, Name = "aaa", Age = 10 });
list.Add(new ExampleClass() { Id = 1, Name = "bbb", Age = 20 });
list.Add(new ExampleClass() { Id = 2, Name = "ccc", Age = 30 });
list.Add(new ExampleClass() { Id = 3, Name = "ddd", Age = 40 });
list.Add(new ExampleClass() { Id = 4, Name = "eee", Age = 50 });
ExampleList1.ItemsSource = list;
ExampleList2.ItemsSource = list;
}
private void Btn1_Click(object sender, RoutedEventArgs e)
{
//リストボックス1の選択アイテムを取り出す
}
private void Btn2_Click(object sender, RoutedEventArgs e)
{
//リストボックス2の選択アイテムを取り出す
}
}
class ExampleClass
{
public int Id { get; set; }
public string Name { get; set; }
public byte Age { get; set; }
}
#リストボックスの中身を取得するメソッドくん
今回の本題です。このメソッドを、リスト選択アイテムを知りたい場所で呼び出します。
//! SelectedItemsの中身を取り出すメソッド
private List<ExampleClass> GetSelectedItems(ListBox listBox)
{
List<ExampleClass> selItems = new List<ExampleClass>();
foreach (var oneItemLine in listBox.SelectedItems)
{
ExampleClass item = oneItemLine as ExampleClass;
selItems.Add(item);
}
return selItems;
}
各ボタンから呼び出します。 対象のコントロールを探す方法は [こちら][2] を参考にしました。 [2]:https://qiita.com/7of9/items/2dd05738a66a71bb3c11 "Visual Studio | WPF > 名前からコントロールを見つける > FindName()"
//! リストボックス1の選択中アイテムを表示する
private void Btn1_Click(object sender, RoutedEventArgs e)
{
// 操作するコントロール
string controlName = "ExampleList1";
// リストボックスを探す
object controlObj = FindName(controlName);
ListBox listBox = (ListBox)controlObj;
// 選択項目が0 => メソッドを出る
if (listBox.SelectedItems.Count == 0)
return;
// 選択中のアイテムを取得する
List<ExampleClass> selItems = GetSelectedItems(listBox);
// メッセージボックスに表示する内容
string message = "";
foreach (var line in selItems)
{
message = message + string.Format("\r\nId:「{0}」 Nmae:「{1}」 Age:「{2}」", line.Id, line.Name, line.Age);
}
message = string.Format($"{controlName} で選択中の項目は\r\n{message}\r\n\r\nです");
MessageBox.Show(message);
}
//! リストボックス2の選択中アイテムを表示する
private void Btn2_Click(object sender, RoutedEventArgs e)
{
// リスト1と大体同じ。ContorolNameを変えるのみ。
}
ボタン1 を押すと
選択中の項目が取り出せました。ボタン2でも同じです。
でもボタン1と2のコードもだいたい同じだからまとめたいですね。まとめた最終的なコードを最後に載せておきます。
#最終的なコード全体
ExampleClassは変わっていないので省略します。
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
List<ExampleClass> list = new List<ExampleClass>();
public MainWindow()
{
InitializeComponent();
list.Add(new ExampleClass() { Id = 0, Name = "aaa", Age = 10 });
list.Add(new ExampleClass() { Id = 1, Name = "bbb", Age = 20 });
list.Add(new ExampleClass() { Id = 2, Name = "ccc", Age = 30 });
list.Add(new ExampleClass() { Id = 3, Name = "ddd", Age = 40 });
list.Add(new ExampleClass() { Id = 4, Name = "eee", Age = 50 });
ExampleList1.ItemsSource = list;
ExampleList2.ItemsSource = list;
}
//! リストボックス1の選択中アイテムを表示する
private void Btn1_Click(object sender, RoutedEventArgs e)
{
// 操作するコントロール
string controlName = "ExampleList1";
ItemShow(controlName);
}
//! リストボックス2の選択中アイテムを表示する
private void Btn2_Click(object sender, RoutedEventArgs e)
{
// 操作するコントロール
string controlName = "ExampleList2";
ItemShow(controlName);
}
// SelectedItemsの中身を取り出す~メッセージ表示メソッド
private void ItemShow(string controlName)
{
// リストボックスを探す
object controlObj = FindName(controlName);
ListBox listBox = (ListBox)controlObj;
// 選択項目が0 => メソッドを出る
if (listBox.SelectedItems.Count == 0)
return;
// 選択中のアイテムを取得する
List<ExampleClass> selItems = GetSelectedItems(listBox);
// メッセージボックスに表示する内容
string message = "";
foreach (var line in selItems)
{
message = message + string.Format("\r\nId:「{0}」 Nmae:「{1}」 Age:「{2}」", line.Id, line.Name, line.Age);
}
message = string.Format($"{controlName} で選択中の項目は\r\n{message}\r\n\r\nです");
MessageBox.Show(message);
}
//! SelectedItemsの中身を取り出すメソッド
private List<ExampleClass> GetSelectedItems(ListBox listBox)
{
List<ExampleClass> selItems = new List<ExampleClass>();
foreach (var oneItemLine in listBox.SelectedItems)
{
ExampleClass item = oneItemLine as ExampleClass;
selItems.Add(item);
}
return selItems;
}
}
#リストボックスの中身を取得するメソッドくん②
以下 2020/09/22 の追記です。
ジェネリックメソッドを用いることで、T を呼び出し元で指定することができます。これにより使いまわし性が向上します。戻り値 selItems
は List<T>
型です。
public List<T> GetSelectedItems<T>(ListBox listBox) where T : class
{
var selItems = new List<T>();
foreach (var oneItemLine in listBox.SelectedItems)
{
var item = oneItemLine as T;
selItems.Add(item);
}
return selItems;
}
これをこのまま```MainWindow.xaml.cs```内に記述してもいいですが、せっかく使いまわしの自由度が増したので、独立したクラスにしたいと思います。
class GetSelectedItems<T> where T : class
{
ListBox listBox;
public GetSelectedItems(ListBox listBox)
{
this.listBox = listBox;
}
//! SelectedItemsの中身を取り出すメソッド
public List<T> Get()
{
var selItems = new List<T>();
foreach (var oneItemLine in listBox.SelectedItems)
{
var item = oneItemLine as T;
selItems.Add(item);
}
return selItems;
}
}
呼び出し元で以下の記述をすることで、SelectedItemsの中身を取り出せます。```var selItems``` は ```List``` 型で、選択中のリストボックスアイテムが入ります。
// リストボックスを探す
object controlObj = FindName(controlName);
ListBox listBox = (ListBox)controlObj;
// 選択中のアイテムを取得する
GetSelectedItems<ExampleClass> g = new GetSelectedItems<ExampleClass>(listBox);
var selItems = g.Get();
#最終的なコード全体②
内容が増えたのでc#の記述全体を書きます。
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
List<ExampleClass> list = new List<ExampleClass>();
public MainWindow()
{
InitializeComponent();
list.Add(new ExampleClass() { Id = 0, Name = "aaa", Age = 10 });
list.Add(new ExampleClass() { Id = 1, Name = "bbb", Age = 20 });
list.Add(new ExampleClass() { Id = 2, Name = "ccc", Age = 30 });
list.Add(new ExampleClass() { Id = 3, Name = "ddd", Age = 40 });
list.Add(new ExampleClass() { Id = 4, Name = "eee", Age = 50 });
ExampleList1.ItemsSource = list;
ExampleList2.ItemsSource = list;
}
//! リストボックス1の選択中アイテムを表示する
private void Btn1_Click(object sender, RoutedEventArgs e)
{
// 操作するコントロール
string controlName = "ExampleList1";
ItemShow(controlName);
}
//! リストボックス2の選択中アイテムを表示する
private void Btn2_Click(object sender, RoutedEventArgs e)
{
// 操作するコントロール
string controlName = "ExampleList2";
ItemShow(controlName);
}
// SelectedItemsの中身を取り出す~メッセージボックス表示メソッド
private void ItemShow(string controlName)
{
// リストボックスを探す
object controlObj = FindName(controlName);
ListBox listBox = (ListBox)controlObj;
// 選択項目が0 => メソッドを出る
if (listBox.SelectedItems.Count == 0)
return;
// 選択中のアイテムを取得する
GetSelectedItems<ExampleClass> g = new GetSelectedItems<ExampleClass>(listBox);
var selItems = g.Get();
// メッセージボックスに表示する内容
string message = "";
foreach (var line in selItems)
{
message = message + string.Format("\r\nId:「{0}」 Nmae:「{1}」 Age:「{2}」", line.Id, line.Name, line.Age);
}
message = string.Format($"{controlName} で選択中の項目は\r\n{message}\r\n\r\nです");
MessageBox.Show(message);
}
}
class ExampleClass
{
public int Id { get; set; }
public string Name { get; set; }
public byte Age { get; set; }
}
class GetSelectedItems<T> where T : class
{
ListBox listBox;
public GetSelectedItems(ListBox listBox)
{
this.listBox = listBox;
}
//! SelectedItemsの中身を取り出すメソッド
public List<T> Get()
{
var selItems = new List<T>();
foreach (var oneItemLine in listBox.SelectedItems)
{
var item = oneItemLine as T;
selItems.Add(item);
}
return selItems;
}
}