横表示は
ListBox.ItemsPanel
ItemsPanelTemplate
StackPanel Orientation="Horizontal"
リストに表示される要素の見た目の変更は
ListBox.ItemTemplate
DataTemplate
StackPanel
Border
TextBlock
/StackPanel
Color(色)とString(色名)のリストをListBoxにBinding
ボタン1,2でリストの先頭の要素を変更、Bindingしてるのでリストの表示も変更される
一番上のListBoxは普通の縦並びで、二番目は横並びに変更したもの
この2つは同じデータをBindingしている
一番下は横並びでColorsクラスの色一覧表示したもの
デザイン画面
<Window x:Class="_20190304_ListBoxのDataTemplate.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_20190304_ListBoxのDataTemplate"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="540">
<Window.Resources>
<local:MyColorConverter x:Key="colorConverter"/>
</Window.Resources>
<Grid Margin="4,20">
<StackPanel>
<Button Name="MyButton1" Content="button1"/>
<Button Name="MyButton2" Content="button2"/>
<ListBox Name="MyListBox1" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Border Background="{Binding Color, Converter={StaticResource colorConverter}}"
Width="20" Height="10" HorizontalAlignment="Left"/>
<CheckBox Content="{Binding Name}"/>
<Ellipse Fill="{Binding Color, Converter={StaticResource colorConverter}}"
Width="10" Height="10" Margin="2"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="MyListBoxHorizontal" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border Background="{Binding Color, Converter={StaticResource colorConverter}}" Width="20" Height="10"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<ListBox Name="MyListBoxWPFColors" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border Background="{Binding Color, Converter={StaticResource colorConverter}}" Width="20" Height="10"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Globalization;
namespace _20190304_ListBoxのDataTemplate
{
<summary>
</summary>
public partial class MainWindow : Window
{
ObservableCollection<MyColorData> myData;
public MainWindow()
{
InitializeComponent();
myData = new ObservableCollection<MyColorData>();
myData.Add(new MyColorData { Color = Colors.BlanchedAlmond, Name = "BlanchedAlmond" });
myData.Add(new MyColorData { Color = Colors.Orange, Name = "Orange" });
myData.Add(new MyColorData { Color = Colors.Olive, Name = nameof(Colors.Olive) });
myData.Add(new MyColorData { Color = Color.FromRgb(0xEB, 0x79, 0x88), Name = "紅梅" });
myData.Add(new MyColorData { Color = Color.FromRgb(242, 216, 223), Name = "桜色" });
this.DataContext = myData;
MyButton1.Click += (s, e) => { myData[0] = new MyColorData { Color = Colors.Tomato, Name = "Tomato" }; };
MyButton2.Click += MyButton2_Click;
System.Reflection.PropertyInfo[] infos = typeof(Colors).GetProperties(
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
var wpfColors = new ObservableCollection<MyColorData>();
foreach (var item in infos)
{
wpfColors.Add(new MyColorData { Color = (Color)item.GetValue(null), Name = item.Name });
}
MyListBoxWPFColors.DataContext = wpfColors;
}
private void MyButton2_Click(object sender, RoutedEventArgs e)
{
myData[0] = new MyColorData { Color = Colors.MediumSpringGreen, Name = nameof(Colors.MediumSpringGreen) };
}
}
public class MyColorData
{
public Color Color { get; set; }
public string Name { get; set; }
}
public class MyColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color c = (Color)value;
return new SolidColorBrush(c);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
BindingのソースとターゲットSource、Target
ソース 元、基本になるほう
ターゲット ソースを元に動きを変えるほう
今回のソースは色の情報リストがソースで、ListBoxがターゲットになる
Color(色)とString(色名)を持つMyColorDataクラスを用意しておいて
適当な5色分のデータからMyColorDataを作成してリストに追加(44~48行目)
使うリストは変更通知をしてくれるObservableCollectionを使う
できたデータリストはアプリ自体(this)のDataContextに指定する(51行目)
これはBindingというか、参照の追加のような、関連付けみたいな感じで
アプリ自体にするとデザイン画面にある要素のどれからでも参照できるようになる
Grid1
┗StackPanel1
┣Button1
┗Button2
ってあったときに
Grid1.DataContext = MyData; どれからでも参照できる
StackPanel1.DataContext = MyData; Grid1以外は参照できる
Button1.DataContext = MyData; Button1だけ参照できる
多分こんな感じで、thisは一番上
16行目のItemsSource="{Binding}"
これでBindingになるみたい、名前がItemsっていう複数形になっているくらいだから、リスト形式のデータの一つ一つを自動で処理してくれるみたい
要素1つ1つをどんなふうに表示するのかの指定が17~24行目
ListBoxのItemTemplateのDataTemplate
この中に自分で好きなように要素を配置して表示できるみたい
StackPanel
┣Borderで色表示
┗TextBlockで色名表示
21行目、String形式の色の名前をTextBlockのTextプロパティにBinding
Text="{Binding Name}"
アプリ自体に関連付けしたのは
this.DataContext = myData
だったから色の名前のフルパスはmyData.NameとかmyData[0].Nameになると思うけど
Nameだけでいいみたい
Bindingの値を変換
20行目は色の表示で、Border要素のBackgroundの色で表現している
BackgroundにはBrushを指定する、けどBindingするのはColorなので
ColorをBrushに変換するConverterを作成
C#に戻ってIValueConverterを継承(追加)したクラスMyColorConverterを作成
99~103行目
Convertの引数の
Valueにデータ元(ソース)のColorが入ってくるので
それをもとにSolidColorBrushを作成して返しているだけ
あとはx:Keyで適当な名前(ColorConverter)をつけて登録完了
これで
XAMLのどこからでもこの名前で使うことができるようになったので
ListBoxのBindingに戻って
Converter={StaticResource 名前}
これでBindingしたColorはSolidColorBrushに変換されて
BorderのBackgroundに指定される
色表示のBorderの横位置の不揃いが気になったら
BorderのHorizontalAlignmentにLeftを指定すれば
左寄せで揃う、いいねえ
Borderの横にTextBlockが積み上げられて
色の横に色名表示になる
TextBlockのかわりにCheckBoxとEllipseと追加で
リストの横表示
横表示リストのMyListBoxHorizontal
40~44行目
ItemTemplateのItemsPanelのItemsPanelTemplate
これにOrientationにHorizontalを指定したStackPanelを指定すれば
横表示のリストになる
ソースの変更でターゲットも変化
Button2クリックでMediumSpringGreenに変更
この変更は要素の中のColorやNameを変更してもターゲット側に無視されるので
要素自体を変更する必要があった
Button1,2でListBoxの表示も変化する
変更通知機能があるObservableCollection
ソースになるデータはこれに入れているけど、変更通知されるのは要素自体が入れ替わるとか追加削除のときだけで、要素の中が変化したときはリストが変化したわけじゃないから変更通知は出ないってことかしらねえ
Button2でランダム色を追加
83~87行目を書き足してButton2をクリックすると
参照したところ
ギットハブ
ブログだから日記
今までは動的に追加削除する要素に対してのBindingは
XAMLじゃなくてコードビハインドっていうのかな、
C#で書いていたのは今回のようなことができることを知らなかったかというか、理解できていなかったからなんだよなあ、あと
XAMLのコードは見づらいとかコメントを挿入しにくいとか入力候補が出ないところがあるからうち間違えしそうとか…結構あるな
でも今回のでListBoxに
XAMLで書くのもいいかもと思った、とくに見た目を変更するDataTemplateのあたりは
C#だと、どう書いていいのかわからないから使い分けかなあ
関連記事
2020/03/17は1年後