WPF ListBox ListBoxItem programmatically selected and changed foreground

FredGrit發表於2024-04-09
//xaml
<Window x:Class="WpfApp49.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp49" WindowState="Maximized"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="{x:Type GroupBox}">
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Background" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="FontSize" Value="50"/>
            <Setter Property="Foreground" Value="Green"/> 
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="True"/> 
                    </MultiTrigger.Conditions>
                    <Setter Property="Foreground" Value="Red"/>
                    <Setter Property="FontSize" Value="60"/> 
                </MultiTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <ComboBox Grid.Row="0" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="30"
                  SelectedItem="{Binding SelectedBook,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                  DisplayMemberPath="Id">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding CbxSelectionChangedCommand}" CommandParameter="{Binding ElementName=lbx}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
        <ListBox x:Name="lbx" Grid.Row="1" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="30" BorderBrush="Black" BorderThickness="3"
                 >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <GroupBox BorderBrush="Blue" BorderThickness="3" Height="300">
                        <Grid  >
                            <Grid.RowDefinitions> 
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Row="0" Text="{Binding Id}"/> 
                            <TextBlock Grid.Row="1" Text="{Binding ISBN}"/> 
                            <TextBlock Grid.Row="2" Text="{Binding Topic}"/>
                        </Grid>
                    </GroupBox>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>


//xaml.cs
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;

namespace WpfApp49
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            MainVM vm = MainVM.VMInstance;
            this.DataContext = vm;
            vm.MainWin = this;
            this.Loaded += vm.MainWindow_Loaded;
        } 
    }
}


//vm.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfApp49
{
    public class MainVM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        }

        public Window MainWin { get; set; }

        private static readonly MainVM vmInstance = new MainVM();
        public static MainVM VMInstance
        {
            get
            {
                return vmInstance;
            }
        }         

        static MainVM()
        {

        }

        private MainVM()
        {
            
        }

        public void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            BooksCollection = new ObservableCollection<Book>();
            for(int i=0;i<1000;i++)
            {
                BooksCollection.Add(new Book()
                {
                    Id=$"{i+1}_{Guid.NewGuid()}",
                    Author=$"Author_{Guid.NewGuid()}",
                    ISBN=$"ISBN_{Guid.NewGuid()}",
                    Name=$"Name_{Guid.NewGuid()}",
                    Topic=$"Topic_{Guid.NewGuid()}"
                });
            }
        }

        private ObservableCollection<Book> booksCollection;
        public ObservableCollection<Book> BooksCollection
        {
            get
            {
                return booksCollection;
            }
            set
            {
                if(value!=booksCollection)
                {
                    booksCollection = value;
                    OnPropertyChanged("BooksCollection");
                }
            }
        }

        private Book selectedBook;
        public Book SelectedBook
        {
            get
            {
                return selectedBook;
            }
            set
            {
                if(value!=selectedBook) 
                {
                    selectedBook = value;
                    OnPropertyChanged("SelectedBook");
                }
            }
        }

        private DelegateCommand cbxSelectionChangedCommand;
        public DelegateCommand CbxSelectionChangedCommand
        {
            get
            {
                if(cbxSelectionChangedCommand == null)
                {
                    cbxSelectionChangedCommand = new DelegateCommand(CbxSelectionChangedCommandExecuted);
                }
                return cbxSelectionChangedCommand;
            }
        }

        private void CbxSelectionChangedCommandExecuted(object obj)
        {
            var lbx = obj as ListBox;
            if(lbx!=null && SelectedBook!=null)
            {
                lbx.ScrollIntoView(SelectedBook);
                lbx.SelectedValue = SelectedBook;
                int pos=lbx.SelectedIndex; 
                ListBoxItem lbi = (ListBoxItem)lbx.ItemContainerGenerator.ContainerFromIndex(lbx.SelectedIndex);
                if(lbi!=null)
                {
                    lbi.IsSelected = true;
                } 
            }
        }
    }

    public class DelegateCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;
        public void RaiseCanExecuteChanged()
        {
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler?.Invoke(this, EventArgs.Empty);
            }
        }

        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public DelegateCommand(Action<object> executeValue, Predicate<object> canExecuteValue)
        {
            _execute = executeValue;
            _canExecute = canExecuteValue;
        }

        public DelegateCommand(Action<object> executeValue) : this(executeValue, null)
        {
        }

        public bool CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }
            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }

    public class Book
    {
        public string Id { get; set; } 
        public string Author { get; set; }
        public string ISBN { get; set; } 
        public string Name { get; set; }
        public string Topic { get; set; }
    }
}

Key parts

1.

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

2.

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="FontSize" Value="50"/>
    <Setter Property="Foreground" Value="Green"/> 
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsSelected" Value="True"/> 
            </MultiTrigger.Conditions>
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="FontSize" Value="60"/> 
        </MultiTrigger>
    </Style.Triggers>
</Style>

 <ComboBox Grid.Row="0" ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
           HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="30"
           SelectedItem="{Binding SelectedBook,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
           DisplayMemberPath="Id">
     <i:Interaction.Triggers>
         <i:EventTrigger EventName="SelectionChanged">
             <i:InvokeCommandAction Command="{Binding CbxSelectionChangedCommand}" CommandParameter="{Binding ElementName=lbx}" />
         </i:EventTrigger>
     </i:Interaction.Triggers>
 </ComboBox>

3.

 private DelegateCommand cbxSelectionChangedCommand;
 public DelegateCommand CbxSelectionChangedCommand
 {
     get
     {
         if(cbxSelectionChangedCommand == null)
         {
             cbxSelectionChangedCommand = new DelegateCommand(CbxSelectionChangedCommandExecuted);
         }
         return cbxSelectionChangedCommand;
     }
 }

 private void CbxSelectionChangedCommandExecuted(object obj)
 {
     var lbx = obj as ListBox;
     if(lbx!=null && SelectedBook!=null)
     {
         lbx.ScrollIntoView(SelectedBook);
         lbx.SelectedValue = SelectedBook;
         int pos=lbx.SelectedIndex; 
         ListBoxItem lbi = (ListBoxItem)lbx.ItemContainerGenerator.ContainerFromIndex(lbx.SelectedIndex);
         if(lbi!=null)
         {
             lbi.IsSelected = true;
         } 
     }
 }

相關文章