Home > Software design >  How to change all items in the ListBox
How to change all items in the ListBox

Time:12-11

I use DataTemplate to repeatedly generate the content of my ListBox. The xaml code is as below:

    <DataTemplate x:Key="singleUnit">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding fileName}" FontSize="20" Foreground="{Binding color}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
            <TextBlock/>
        </StackPanel>
    </DataTemplate>

    <ListBox Name="MyListBox" Width="300" Height="600">
    </ListBox>

And the cs code is:

private void Show()
{
    const int TotalCount = 100;
    for (int i = 0; i < TotalCount; i  )
    {
        ContentControl cc = new ContentControl();
        cc.ContentTemplate = this.Resources["singleUnit"] as DataTemplate;
        DataModel dm = new DataModel();
        dm.fileName = "myfile"   i;
        dm.color = new SolidColorBrush(Colors.Blue);
        cc.Content = dm;
        MyListBox.Items.Add(cc);
    }

    MyListBox.ScrollIntoView(MyListBox.Items[TotalCount / 2]);
}

Above code will generate below UI: enter image description here

And I hope to change all the item's color: currently each item, the fileName's foreground color is blue. And I hope to change it to like green when the button is pressed.

This is like that user changes the color theme with some selection operation. And when the color changes, all the other things should be not changed, e.g. the position of the scroll bar.

The difficulty is that I use template to generate the content, and how to iterate each item and modify it.

I put the workable demo code on my Github: https://github.com/tomxue/ChangeListBox.git You could start from it. Thanks!

CodePudding user response:

I made your code work but it is still not perfectly right as you should have per each view a view-model and bind between them. Your MainForm - should have a MainFormViewModel. Your File Items - should have VmFile (or ViewModelFile as I wrote in the example) You should be using ICommand to bind the button and not by having an event as you did. Shortly put, I don't think you are working correct with MVVM, I advise you to read more about MVVM.

Copy to your .xaml file:

 <Window x:Class="WpfApp14.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:WpfApp14"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        
        <Grid>
            <ListBox Name="MyListBox" Width="300" Height="600">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding FileName}" FontSize="20" Foreground="{Binding Color}"
                                       HorizontalAlignment="Left" VerticalAlignment="Top"/>
                            <TextBlock/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
    
            </ListBox>
            <Button Content="Change color theme" HorizontalAlignment="Left" Margin="56,126,0,0" VerticalAlignment="Top" Width="164" Click="Button_Click" Height="36"/>
        </Grid>
    </Window>

Copy to your .cs file:

using System;
using System.Collections.Generic;
using System.ComponentModel;
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;

namespace WpfApp14
{
    public class ViewModelFile : INotifyPropertyChanged
    {
        private string filename;
        private SolidColorBrush solidColorBrush;

        public event PropertyChangedEventHandler PropertyChanged;

        public string FileName 
        { 
            get =>filename;
            set 
            {
                filename = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FileName)));
            }
        }

        public SolidColorBrush Color
        {
            get => solidColorBrush;
            set
            {
                solidColorBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Color)));
            }
        }

        
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Refresh();
        }

        private void Refresh()
        {
            const int TotalCount = 100;
            for (int i = 0; i < TotalCount; i  )
            {
                ViewModelFile vm = new ViewModelFile
                {
                    FileName = "myfile"   i,
                    Color = new SolidColorBrush(Colors.Blue)
                };
                MyListBox.Items.Add(vm);
            }
            MyListBox.ScrollIntoView(MyListBox.Items[TotalCount / 2]);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Do something to change all fileName items' forground color to red.
            // For example if user changes the color theme, and we should just change some UI color
            // while not changing any other part, e.g. the position of scrollbar
            foreach (var item in MyListBox.Items)
                ((ViewModelFile)item).Color = new SolidColorBrush(Colors.Red);
        }
    }
}
  • Related