WPFのListBox、ItemTemplateで表示変更したListBoxを動的作成したいのでXAMLじゃなくてC#コードで書いてみた
ListBoxを動的追加したい、それもItemTemplateで表示を変更したListBox、さらにBindingも
アプリのコードとダウンロード先
ファイル名:20200317_ListBox.zip
github.com
ListBoxの設定をXAMLで書いた部分
<ListBox x:Name="MyListBox1" ItemsSource="{Binding}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Border Width="20" Height="10" Background="{Binding Brush}"/> <TextBlock Text="{Binding ColorCode}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox>
これにBindingするデータは、BrushがSolidColorBrushで色の表示、もう1つのColorCodeはBrushに使っている色をテキスト形式にしたもの、これを指定すると
こうなる
ListBox1つだけならこれでいい、3個くらいでも上のXAMLをコピペで書いてもいい、でもそれ以上はめんどくさいし、アプリ起動後にListBoxを追加したいこともある!これはC#で書ければできるってことで
上のXAMLをC#コードで書いたのが
//ListBoxを動的作成追加 private void AddListBox() { var listBox = new ListBox(); //ListBoxのItemsSourceのBindingはソースの指定もない空のBinding listBox.SetBinding(ListBox.ItemsSourceProperty, new Binding()); //listboxの要素追加方向を横にする var stackPanel = new FrameworkElementFactory(typeof(StackPanel)); stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); var itemsPanel = new ItemsPanelTemplate() { VisualTree = stackPanel }; listBox.ItemsPanel = itemsPanel; //ListBoxのアイテムテンプレート作成、設定 //ItemTemplate作成、Bindingも設定する //縦積みのstackPanelにBorderとTextBlock //StackPanel(縦積み) //┣Border //┗TextBlock var border = new FrameworkElementFactory(typeof(Border)); border.SetValue(WidthProperty, 20.0); border.SetValue(HeightProperty, 10.0); border.SetBinding(BackgroundProperty, new Binding(nameof(MyData.Brush))); var textBlock = new FrameworkElementFactory(typeof(TextBlock)); textBlock.SetBinding(TextBlock.TextProperty, new Binding(nameof(MyData.ColorCode))); var panel = new FrameworkElementFactory(typeof(StackPanel)); //panel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);//横積み panel.AppendChild(border); panel.AppendChild(textBlock); var dt = new DataTemplate(); dt.VisualTree = panel; listBox.ItemTemplate = dt; //追加(表示) MyStackPanel.Children.Add(listBox); //表示するデータ作成、設定 listBox.DataContext = MakeMyDataList(MakeColors(5)); }
すっごい長くなった
XAMLとC# を比較してみる
ListBoxのItemsSourceのBinding部分
<ListBox x:Name="MyListBox1" ItemsSource="{Binding}">
C#だと
listBox.SetBinding(ListBox.ItemsSourceProperty, new Binding());
これはほとんど変わらない、Bindingはソースとかパスとかも設定していないんだけど、これが必要、よくわからん
ItemTemplateを使ってListBoxの要素の表示を変更部分
StackPanel
┣Border
┗TextBlock
に設定している部分
<ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Border Width="20" Height="10" Background="{Binding Brush}"/> <TextBlock Text="{Binding ColorCode}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate>
C#だと
var border = new FrameworkElementFactory(typeof(Border)); border.SetValue(WidthProperty, 20.0); border.SetValue(HeightProperty, 10.0); border.SetBinding(BackgroundProperty, new Binding(nameof(MyData.Brush))); var textBlock = new FrameworkElementFactory(typeof(TextBlock)); textBlock.SetBinding(TextBlock.TextProperty, new Binding(nameof(MyData.ColorCode))); var panel = new FrameworkElementFactory(typeof(StackPanel)); //panel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);//横積み panel.AppendChild(border); panel.AppendChild(textBlock); var dt = new DataTemplate(); dt.VisualTree = panel; listBox.ItemTemplate = dt;
ここが一番長くなるけど以前にも試したので、これであっているはず
ItemsPanelTemplateを使って、ListBoxの要素の並び方向を横にするための部分
<ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ListBox.ItemsPanel>
C#だと
//listboxの要素追加方向を横にする var stackPanel = new FrameworkElementFactory(typeof(StackPanel)); stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); var itemsPanel = new ItemsPanelTemplate() { VisualTree = stackPanel }; listBox.ItemsPanel = itemsPanel;
これはあっているかわからん
コード全部
XAML
<Window x:Class="_20200317_ListBox.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:_20200317_ListBox" mc:Ignorable="d" Title="MainWindow" Height="450" Width="480"> <Grid Margin="10"> <StackPanel x:Name="MyStackPanel"> <StackPanel.Resources> <Style TargetType="ListBox"> <Setter Property="Margin" Value="0,2"/> </Style> </StackPanel.Resources> <Button x:Name="Button1" Content="ListBox追加" Click="Button1_Click"/> <ListBox x:Name="MyListBox1" ItemsSource="{Binding}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Border Width="20" Height="10" Background="{Binding Brush}"/> <TextBlock Text="{Binding ColorCode}"/> </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.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Collections.ObjectModel; //ItemTemplateで表示を変更したListBoxを動的作成したい namespace _20200317_ListBox { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //XAMLで用意してあるListBoxにデータ追加 MyListBox1.DataContext = MakeMyDataList(MakeColors(5)); } //ListBoxを動的作成追加 private void AddListBox() { var listBox = new ListBox(); //ListBoxのItemsSourceのBindingはソースの指定もない空のBinding listBox.SetBinding(ListBox.ItemsSourceProperty, new Binding()); //listboxの要素追加方向を横にする var stackPanel = new FrameworkElementFactory(typeof(StackPanel)); stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); var itemsPanel = new ItemsPanelTemplate() { VisualTree = stackPanel }; listBox.ItemsPanel = itemsPanel; //ListBoxのアイテムテンプレート作成、設定 //ItemTemplate作成、Bindingも設定する //縦積みのstackPanelにBorderとTextBlock //StackPanel(縦積み) //┣Border //┗TextBlock var border = new FrameworkElementFactory(typeof(Border)); border.SetValue(WidthProperty, 20.0); border.SetValue(HeightProperty, 10.0); border.SetBinding(BackgroundProperty, new Binding(nameof(MyData.Brush))); var textBlock = new FrameworkElementFactory(typeof(TextBlock)); textBlock.SetBinding(TextBlock.TextProperty, new Binding(nameof(MyData.ColorCode))); var panel = new FrameworkElementFactory(typeof(StackPanel)); //panel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);//横積み panel.AppendChild(border); panel.AppendChild(textBlock); var dt = new DataTemplate(); dt.VisualTree = panel; listBox.ItemTemplate = dt; //追加(表示) MyStackPanel.Children.Add(listBox); //表示するデータ作成、設定 listBox.DataContext = MakeMyDataList(MakeColors(5)); } private List<Color> MakeColors(int count) { var vs = new byte[count * 3]; var r = new Random(); r.NextBytes(vs); var colors = new List<Color>(); for (int i = 0; i < vs.Length; i += 3) { colors.Add(Color.FromRgb(vs[i], vs[i + 1], vs[i + 2])); } return colors; } private ObservableCollection<MyData> MakeMyDataList(List<Color> colors) { var list = new ObservableCollection<MyData>(); for (int i = 0; i < colors.Count; i++) { list.Add(new MyData(colors[i])); } return list; } private void Button1_Click(object sender, RoutedEventArgs e) { AddListBox(); } } //表示するデータ用 public class MyData { //Bindingで使う項目はpublicでgetが必要 public SolidColorBrush Brush { get; set; } public string ColorCode { get; set; } public MyData(Color color) { Brush = new SolidColorBrush(color); ColorCode = color.ToString(); } } }
関連記事
一年前も同じことしてたけど、ほとんど忘れてた
gogowaten.hatenablog.com