質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

1028閲覧

動的に複数作成した ListBox から特定の ListBox の指定行に背景色をセットしたい

byori

総合スコア71

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2022/08/17 06:22

編集2022/08/18 15:28

動的に ListBox を下記のコードで横にいくつか並べるように作製しております。

それ自身問題なくできておりますが、作成・表示後に再度その listBox を参照したいことが発生しました。
イメージ説明
listBox 内のデータをバーコードリーダーで読み込ませた番号と一致する番号、例えば図の F2221346 番号の行の背景色を変更したい。

C#

1 private void AddListBox(List<string> list) 2 { 3 // ListBoxを動的作成追加(https://gogowaten.hatenablog.com/entry/2020/03/17/133941)参照 4 var listBox = new ListBox(); 5 6 // ListBoxのItemsSourceのBindingはソースの指定もない空のBinding 7 listBox.SetBinding(ListBox.ItemsSourceProperty, new Binding()); 8 listBox.SetValue(TextBlock.MarginProperty, new Thickness(2, 5, 0, 5)); 9 10 // ListBoxのアイテムテンプレート作成、設定 11 var panel = new FrameworkElementFactory(typeof(StackPanel)); 12 panel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); 13 //panel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); 14 // 番号 15 var textBlock = new FrameworkElementFactory(typeof(TextBlock)); 16 textBlock.SetBinding(TextBlock.TextProperty, new Binding(nameof(DoctorList.Hyohon))); 17 textBlock.SetValue(TextBlock.MarginProperty, new Thickness(5, 1, 5, 1)); 18 textBlock.SetValue(FrameworkElement.WidthProperty, (double)50); 19 /* textBlock.SetValue(FrameworkElement.HeightProperty, (double)15); */ 20 panel.AppendChild(textBlock); 21 // 名前 22 var textBlock2 = new FrameworkElementFactory(typeof(TextBlock)); 23 textBlock2.SetBinding(TextBlock.TextProperty, new Binding(nameof(DoctorList.KanjaMei))); 24 textBlock2.SetValue(TextBlock.MarginProperty, new Thickness(0, 1, 5, 1)); 25 textBlock2.SetValue(FrameworkElement.WidthProperty, (double)80); 26 panel.AppendChild(textBlock2); 27 // チェック 28 var check = new FrameworkElementFactory(typeof(CheckBox)); 29 check.SetBinding(CheckBox.IsCheckedProperty, new Binding(nameof(DoctorList.scCheck))); 30 check.SetValue(TextBlock.MarginProperty, new Thickness(0, 1, 2, 1)); 31 panel.AppendChild(check); 32 // ギムザ 33 var check2 = new FrameworkElementFactory(typeof(CheckBox)); 34 check2.SetBinding(CheckBox.IsCheckedProperty, new Binding(nameof(DoctorList.gCheck))); 35 check2.SetValue(TextBlock.MarginProperty, new Thickness(0, 1, 2, 1)); 36 panel.AppendChild(check2); 37 38 var dt = new DataTemplate(); 39 dt.VisualTree = panel; 40 listBox.ItemTemplate = dt; 41 42 //追加(表示) 43 panel2.Children.Add(listBox); 44 45 46 // タイトルをつけるために下記を作成 47 // 48 var Box = new TextBox(); 49 Box.SetBinding(ListBox.ItemsSourceProperty, new Binding()); 50 Box.SetValue(TextBlock.MarginProperty, new Thickness(2, 5, 0, 5)); 51 var title = new FrameworkElementFactory(typeof(StackPanel)); 52 title.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); 53 var text = new FrameworkElementFactory(typeof(TextBlock)); 54 text.SetBinding(TextBlock.TextProperty, new Binding(nameof(DoctorList.Dr))); 55 text.SetValue(TextBlock.MarginProperty, new Thickness(20, 1, 5, 1)); 56 text.SetValue(FrameworkElement.WidthProperty, (double)165); 57 text.SetValue(FrameworkElement.HeightProperty, (double)20); 58 text.SetValue(TextBlock.FontSizeProperty, 18.0); 59 title.AppendChild(text); 60 61 62 FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel)); 63 stackPanelFactory.AppendChild(title); 64 // CellTemplate を作成 65 ControlTemplate template = new ControlTemplate(); 66 // 作成したビジュアルツリーをセット 67 template.VisualTree = stackPanelFactory; 68 Box.Template = template; 69 70 //追加(表示) 71 panel1.Children.Add(Box); 72 73 74 //表示するデータ作成、設定 75 listBox.DataContext = MakeList(list); 76 Box.DataContext = MakeList(list); 77 } 78 79 Model._custmer に listBox を表示するデータが入っています。番号でそのデータを抽出します。 80 81 private System.Collections.ObjectModel.ObservableCollection<DoctorList> MakeList(List<string> lst) 82 { 83 var list = new System.Collections.ObjectModel.ObservableCollection<DoctorList>(); 84 for (int i = 0; i < lst.Count; i++) 85 { 86 var custum = Model._custmer.Where(x => x.Hyohon == lst[i]).FirstOrDefault(); 87 88 list.Add(new DoctorList(custum.No, custum.Hyohon, custum.IinCode, custum.KanjaMei, custum.Bui, custum.Check, custum.Dr, 89 custum.scCheck, custum.gCheck, Model._custmer[i].ForceSet)); 90 } 91 92 return list; 93 }

xaml

1 <ScrollViewer HorizontalScrollBarVisibility="Auto" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4" Margin="5"> 2 <StackPanel Orientation="Vertical"> 3 <DockPanel x:Name="panel1" /> 4 <StackPanel Orientation="Horizontal"> 5 <DockPanel x:Name="panel2" /> 6 </StackPanel> 7 </StackPanel> 8 </ScrollViewer>

イメージ説明
コントロールの一覧を表示しよう (VisualTreeHelperとLogicalTreeHelperの違い) その①より
https://qiita.com/furugen/items/185c1815625e2a58d0a8
下記でコントロールが多数出てきますが、ここからどうやって目的のコントロールを見つけるのでしょうか?

C#

1 private void ShowVisualControl(DependencyObject tgt, int position = 0) 2 { 3 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(tgt); i++) 4 { 5 DependencyObject childObj = VisualTreeHelper.GetChild(tgt, i); 6 // ログ出力 7 ShowLog(childObj, position); 8 list.Add(childObj.ToString()); 9 10 if (VisualTreeHelper.GetChildrenCount(childObj) > 0) 11 { 12 int nextPosition = position + 1; 13 ShowVisualControl(childObj, nextPosition); 14 } 15 } 16 } 17 private static void ShowLog(DependencyObject tgt, int position = 0) 18 { 19 string tab = null; 20 string baseInfo = tgt.ToString(); 21 22 for (int i = 0; i < position; i++) 23 { 24 tab += "\t"; 25 } 26 27 // 下記情報を出力 28 // 基本情報 : コンテンツ 29 System.Diagnostics.Debug.WriteLine(tab + baseInfo); 30 }

Windows11 VS2019 WPF C#

【修正】
自己レスです。
まだ、答え近づいているのかわかりませんが、
ListBox lbl = (ListBox)panel2.Children.OfType<FrameworkElement>().FirstOrDefault(a => a.Name == "");
var lb = panel2.Children.OfType<FrameworkElement>();

でも、 ListBox が探せました。

イメージ説明

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

listBox 内のデータをバーコードリーダーで読み込ませた番号と一致する番号、例えば図の F2221346 番号の行の背景色を変更したい。

ListBoxは仮想化が有効なので、必ずしもその(番号が一致する行の)ListBoxItemが存在するかはわかりません。
通常はListBoxItem等のトリガーで変更します。

そもそもFrameworkElementFactoryで、動的に生成すること自体筋が悪いです。

要は何か元になるリストがあって、その一部だけ抽出したリストが複数あるってことですよね?

.NET6です^^ NuGet Gallery | CommunityToolkit.Mvvm 8.0.0

xml

1<Window 2 x:Class="Q78aqeaolcdtqmb.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Q78aqeaolcdtqmb" 6 Width="1000" 7 Height="450"> 8 <Window.Resources> 9 <DataTemplate DataType="{x:Type local:Custmers}"> 10 <StackPanel Margin="2"> 11 <TextBlock Text="{Binding [0].Dr}" /> 12 <!-- カラム合わせが面倒なのでListView --> 13 <ListView ItemsSource="{Binding}"> 14 <ListView.Resources> 15 <!-- ヘッダー消し --> 16 <Style TargetType="GridViewColumnHeader"> 17 <Setter Property="Template" Value="{x:Null}" /> 18 </Style> 19 </ListView.Resources> 20 <ListView.ItemContainerStyle> 21 <Style TargetType="ListViewItem"> 22 <Style.Triggers> 23 <!-- プロパティとバインドして色を変える --> 24 <DataTrigger Binding="{Binding Highlight}" Value="True"> 25 <Setter Property="Background" Value="Red" /> 26 </DataTrigger> 27 </Style.Triggers> 28 </Style> 29 </ListView.ItemContainerStyle> 30 <ListView.View> 31 <GridView> 32 <GridViewColumn DisplayMemberBinding="{Binding No}" /> 33 <GridViewColumn DisplayMemberBinding="{Binding KanjaMei}" /> 34 <GridViewColumn> 35 <GridViewColumn.CellTemplate> 36 <DataTemplate> 37 <CheckBox IsChecked="{Binding ScCheck}" /> 38 </DataTemplate> 39 </GridViewColumn.CellTemplate> 40 </GridViewColumn> 41 </GridView> 42 </ListView.View> 43 </ListView> 44 </StackPanel> 45 </DataTemplate> 46 </Window.Resources> 47 48 <DockPanel> 49 <Button 50 Click="AddButton_Click" 51 Content="add" 52 DockPanel.Dock="Top" /> 53 <Button 54 Click="HighlightButton_Click" 55 Content="highlight" 56 DockPanel.Dock="Top" /> 57 <Grid> 58 <Grid.ColumnDefinitions> 59 <ColumnDefinition /> 60 <ColumnDefinition /> 61 </Grid.ColumnDefinitions> 62 <!-- 元データ --> 63 <DataGrid 64 x:Name="dataGrid" 65 AutoGenerateColumns="True" 66 ItemsSource="{Binding Model.Custmers}" /> 67 68 <ScrollViewer 69 Grid.Column="1" 70 Margin="5" 71 HorizontalScrollBarVisibility="Auto"> 72 <ItemsControl ItemsSource="{Binding CustmersList}"> 73 <ItemsControl.ItemsPanel> 74 <ItemsPanelTemplate> 75 <StackPanel Orientation="Horizontal" /> 76 </ItemsPanelTemplate> 77 </ItemsControl.ItemsPanel> 78 </ItemsControl> 79 </ScrollViewer> 80 </Grid> 81 </DockPanel> 82</Window>

cs

1using System; 2using System.Collections.Generic; 3using System.Collections.ObjectModel; 4using System.Linq; 5using System.Windows; 6using CommunityToolkit.Mvvm.ComponentModel; 7 8namespace Q78aqeaolcdtqmb; 9 10 11public class Model 12{ 13 public Custmers Custmers { get; } = new(); 14} 15 16public class Custmer : ObservableObject 17{ 18 public int No { get; } 19 public string Hyohon { get; } 20 public string KanjaMei { get; } 21 public string Dr { get; } 22 public bool ScCheck { get; set; } 23 24 public bool Highlight { get => highlight; set => SetProperty(ref highlight, value); } 25 private bool highlight; 26 27 public Custmer(int no, string hyohon, string kanjaMei, string dr, bool scCheck) 28 { 29 (No, Hyohon, KanjaMei, Dr, ScCheck) = (no, hyohon, kanjaMei, dr, scCheck); 30 } 31 32 33 // ダミー作成用 34 private static int no = 1300; 35 private static Random r = new(); 36 private static string k = "アイウエオカキクケコサシスセソタチツテトナニヌネノナヒフヘホマミムメモヤユヨラリルレロワ"; 37 public Custmer() 38 { 39 No = ++no; 40 Hyohon = $"F222{No}"; 41 KanjaMei = string.Join("", Enumerable.Range(0, r.Next(5, 10)).Select(x => k[r.Next(k.Length)])); 42 Dr = $"dr{No}"; 43 ScCheck = false; 44 } 45} 46 47public class Custmers : List<Custmer> { } // xamlでジェネリック指定できないので型を作る 48 49 50public partial class MainWindow : Window 51{ 52 public Model Model { get; } = new(); 53 54 public ObservableCollection<Custmers> CustmersList { get; } = new(); 55 56 57 public MainWindow() 58 { 59 InitializeComponent(); 60 61 foreach (var _ in Enumerable.Range(1, 100)) 62 { 63 Model.Custmers.Add(new Custmer()); 64 } 65 66 DataContext = this; 67 } 68 69 private void AddButton_Click(object sender, RoutedEventArgs e) 70 { 71 var custmers = new Custmers(); 72 // DataGridで選択中を抽出 73 custmers.AddRange(dataGrid.SelectedItems.Cast<Custmer>()); 74 // ItemsControlに追加 75 CustmersList.Add(custmers); 76 } 77 78 private void HighlightButton_Click(object sender, RoutedEventArgs e) 79 { 80 // ハイライトを全クリア 81 foreach (var custmer in Model.Custmers) 82 { 83 custmer.Highlight = false; 84 } 85 86 // DataGridで選択中をハイライト 87 foreach (Custmer custmer in dataGrid.SelectedItems) 88 { 89 custmer.Highlight = true; 90 } 91 } 92}

アプリ画像


Model._custmer[i].ForceSetは、custum.ForceSetではないですか?
_custmerlstの数は無関係ですから、iでアクセスする意味がないように思うのですが?

投稿2022/08/17 13:57

TN8001

総合スコア9244

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

byori

2022/08/18 00:38

TN8001 様、いつもお世話になっております。 > ListBoxは仮想化が有効なので、必ずしもその(番号が一致する行の)ListBoxItemが存在するかはわかりません。 なるほど、将来的なバグが潜んでいるかもしれない手段はやめた方がいいですね。 > 要は何か元になるリストがあって、その一部だけ抽出したリストが複数あるってことですよね? その通りです。 <Window.Resources>   <DataTemplate DataType="{x:Type vm:Custmers}">    : <ItemsControl ItemsSource="{Binding CustmersList}"> リソースでの定義とItemsControl としてこんな使い方があることを知らなかったんですね。  いつも勉強になります。 ありがとうございます。
TN8001

2022/08/18 04:01

> リソースでの定義とItemsControl としてこんな使い方があることを知らなかったんですね。 DataTemplateをWindow.Resourcesに入れた深い意味はありません(なんとなくごちゃっとするかな?というのと、最初に目に入るようにという程度です) 今回の場合は、ItemsControl.ItemTemplateに入れても同じです。 例えば同じDataTypeのDataTemplateを複数の場所(ItemsControl.ItemTemplate・Grid.Resources・Window.Resources等々)に入れた場合、直近のDataTemplateを使用します。 あるところでは横長に・別の場所では縦長に・あるいは簡略表示・詳細表示等々、同一データでも場所によって見せ方を変えることができます。 DataTemplateはView設計の一番キモの部分です。 [データ テンプレートの概要 - WPF .NET Framework | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/data/data-templating-overview) ItemsControlは個人的に一番面白いコントロールです。 [ItemsControl 攻略 ~ 外観のカスタマイズ | grabacr.nét](http://grabacr.net/archives/1240) この辺りを使えるようになってくると俄然WPFが楽しくなってきますし、「なるほど。これがMVVMか!」と急に目の前が開けた気分に(私は)なりました。 byoriさんもがんばってください^^
byori

2022/08/18 06:28

いつも応援ありがとうございます。!(^^)!
guest

0

var listBox = new ListBox();

ローカル変数でListBoxのインスタンスを受けてしまうと、その関数が終わればその変数は消滅してしまうので、インスタンス変数とかグローバル変数とかのリストにでも入れるようにしよう
後でそいつを参照して操作ができます

投稿2022/08/17 08:48

y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/08/17 10:26

フォーム上に置いているので、ずっとあります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問