Highlight ListBox SelectedItem Programmically

BigH61 581 Reputation points
2023-03-04T20:59:44.9566667+00:00

How to highlight ListBox SelectedItem Programmically.

My ListBox code is as follow, however when the SelectedItem is set programmically the item is not highlighted, even though it is highlighted when an item is selected manually. Thank you for your assistance.


<ListBox x:Name="SeriesListBox"  ItemsSource="{Binding SeriesCollection}" SelectedItem="{Binding SelectedSeriesItem}"  Height="140" VerticalAlignment="Top">
                                    <ListBox.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <UniformGrid x:Name="SeriesUniformGrid" Rows="1" Width="{Binding SeriesGridWidth}" HorizontalAlignment="Left"/>
                                        </ItemsPanelTemplate>
                                    </ListBox.ItemsPanel>
                                    <ListBox.ItemTemplate>
                                        <DataTemplate>
                                            <Image Height="100" Width="100" VerticalAlignment="Center" Source="{Binding Path=Image, Mode=OneWay, Converter={StaticResource NullImageConverter }}" Margin="5"/>
                                        </DataTemplate>
                                    </ListBox.ItemTemplate>
                                        <behaviors:Interaction.Triggers>
                                            <behaviors:EventTrigger EventName="SelectionChanged">
                                                <behaviors:InvokeCommandAction Command="{Binding SeiesSelectionChangedCommand}" CommandParameter="{Binding ElementName=SeriesListBox, Path=SelectedItem}"/>
                                            </behaviors:EventTrigger>
                                        </behaviors:Interaction.Triggers>
                                </ListBox>
Developer technologies | Windows Presentation Foundation
Developer technologies | C#
Developer technologies | C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
0 comments No comments
{count} votes

Answer accepted by question author
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2023-03-05T06:22:53.7766667+00:00

    Hi,
    You can use the style globally for ListBoxItems that includes keeping the selected item highlighted even when the control loses focus. See my demo:

    <Window x:Class="WpfApp1.Window045"
            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:WpfApp045"
            xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
            mc:Ignorable="d"
            Title="BigH61_230305" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Window.Resources>
        <local:NullImageConverter x:Key="NullImageConverter"/>
        <Style TargetType="{x:Type ListBoxItem}">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border
                        x:Name="ItemBorder"
                        Padding="{TemplateBinding Padding}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                  <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
    
                <ControlTemplate.Triggers>
                  <!--  Use the same colours for selected items, whether or not the control has focus  -->
                  <Trigger Property="IsSelected" Value="true">
                    <Setter TargetName="ItemBorder" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
                  </Trigger>
    
                  <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                  </Trigger>
                </ControlTemplate.Triggers>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </Window.Resources>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="Auto"/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <ListBox x:Name="SeriesListBox" ItemsSource="{Binding SeriesCollection}" SelectedItem="{Binding SelectedSeriesItem}"  Height="140" VerticalAlignment="Top">
          <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
              <UniformGrid x:Name="SeriesUniformGrid" Rows="1" Width="{Binding SeriesGridWidth}" HorizontalAlignment="Left"/>
            </ItemsPanelTemplate>
          </ListBox.ItemsPanel>
          <ListBox.ItemTemplate>
            <DataTemplate>
              <Image Height="100" Width="100" VerticalAlignment="Center" Source="{Binding Path=Image, Mode=OneWay, Converter={StaticResource NullImageConverter }}" Margin="5"/>
            </DataTemplate>
          </ListBox.ItemTemplate>
          <behaviors:Interaction.Triggers>
            <behaviors:EventTrigger EventName="SelectionChanged">
              <behaviors:InvokeCommandAction Command="{Binding SeiesSelectionChangedCommand}" CommandParameter="{Binding ElementName=SeriesListBox, Path=SelectedItem}"/>
            </behaviors:EventTrigger>
          </behaviors:Interaction.Triggers>
        </ListBox>
        <Button Grid.Row="1" Content="Select New" Command="{Binding}" Margin="10"/>
      </Grid>
    </Window>
    

    ViewModel:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    
    namespace WpfApp045
    {
    	public class ViewModel : INotifyPropertyChanged, ICommand
    	{
    		public ViewModel()
    		{
    			for (int i = 1; i < 10; i++)
    			{
    				FormattedText text = new FormattedText(i.ToString(),
    				new CultureInfo("en-us"),
    				FlowDirection.LeftToRight,
    				new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Normal, new FontStretch()),
    				24,
    				Brushes.Red, 1.0);
    				DrawingVisual visual = new DrawingVisual();
    				DrawingContext drawingContext = visual.RenderOpen();
    				drawingContext.DrawText(text, new Point(2, 2));
    				drawingContext.Close();
    				var bitmap = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Default);
    				bitmap.Render(visual);
    				col.Add(new Data() { ID = i, Image = bitmap });
    			}
    			cvs.Source = col;
    		}
    
    		private ObservableCollection<Data> col = new ObservableCollection<Data>();
    		// SeriesCollection member
    		private CollectionViewSource cvs = new CollectionViewSource();
    		public ICollectionView SeriesCollection { get => cvs.View; }
    
    		private Data _selectedSeriesItem;
    		public Data SelectedSeriesItem
    		{
    			get => this._selectedSeriesItem;
    			set
    			{
    				this._selectedSeriesItem = value;
    				OnPropertyChanged();
    			}
    		}
    
    
    		private RelayCommand? _seiesSelectionChangedCommand;
    
    
    		public RelayCommand SeiesSelectionChangedCommand
    		{
    			get { return _seiesSelectionChangedCommand ?? (_seiesSelectionChangedCommand = new RelayCommand(param => SeiesSelectionChangedHandler(), param => true)); }
    		}
    
    		public int SeriesGridWidth { get; set; } = 600;
    
    		private void SeiesSelectionChangedHandler()
    		{
    			Debug.Print(SelectedSeriesItem.ID.ToString());
    		}
    
    		private Random rnd = new Random();
    		public event EventHandler? CanExecuteChanged;
    		public bool CanExecute(object? parameter) => true;
    		public void Execute(object? parameter) => SelectedSeriesItem = col[rnd.Next(0, col.Count)];
    
    		// INotifyPropertyChanged
    #pragma warning disable CS8612 // Nullability of reference types in type doesn't match implicitly implemented member.
    		public event PropertyChangedEventHandler PropertyChanged;
    		public void OnPropertyChanged([CallerMemberName] string info = "") =>
    				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
    	}
    
    	public class Data
    	{
    		public int ID { get; set; }
    		public ImageSource? Image { get; set; }
    	}
    
    	public class NullImageConverter : IValueConverter
    	{
    		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    		{
    			return value;
    		}
    
    		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    		{
    			throw new NotImplementedException();
    		}
    	}
    
    #pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes).
    #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
    	public class RelayCommand : ICommand
    	{
    		private readonly Predicate<object> _canExecute;
    		private readonly Action<object> _action;
    		public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
    		public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
    		public void Execute(object o) => _action(o);
    		public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
    		public event EventHandler CanExecuteChanged
    		{
    			add { CommandManager.RequerySuggested += value; }
    			remove { CommandManager.RequerySuggested -= value; }
    		}
    	}
    }
    

    Result:

    x


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.