Home > Software engineering >  Style SelectedItem in ListBox upon Load WPF
Style SelectedItem in ListBox upon Load WPF

Time:11-25

I have a ListBox, as such:

<ListBox
    //other stuff
    ItemsSource="{Binding ViewModels, UpdateSourceTrigger=PropertyChanged}"
    SelectedItem="{Binding SelectedThing, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
    <ListBox.ItemContainerStyle>
          <Style TargetType="ListBoxItem"> 
                <Style.Triggers>
                       <Trigger Property="IsSelected" Value="True">
                             <Setter Property="Background" Value="Purple" />
                       </Trigger>
                </Style.Triggers>
          </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

ViewModel.cs:

public SomeType SelectedThing
{
     get => selectedThing;
     set => //set with INotifyPropertyChanged
}

public ObservableCollection<SomeType> ViewModels
{
     get => viewModels;
     set => //set with INotifyPropertyChanged
}

It's possible that SelectedThing is defined in the ViewModel when loading the app, so I want it to be styled accordingly.

It works great when I open the app and then click on an item, but how can the style be applied on load?

I tried with:

<Style.Triggers>
      <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="True">
            <Setter Property="Background" Value="Purple" />
      </DataTrigger>
</Style.Triggers>

But every item of the ListBox is enabled, so it applies it to every item upon load.

EDIT:

After debugging a bit, I found out that when setting SelectedThing on load, SelectedItem remains null.

EDIT:

Here is the OnLoaded method in the ViewModel, where I am setting SelectedThing if the user has selected it while previously using the app. The purpose is to keep the selection after closing and reopening the app.

public IAsyncRelayCommand onl oadedCommand { get; set; }

In the constructor:

OnLoadedCommand = new AsyncRelayCommand(OnLoaded);

In the View:

<b:Interaction.Triggers>
    <b:EventTrigger EventName="Loaded">
        <b:InvokeCommandAction Command="{Binding onl oadedCommand}" />
    </b:EventTrigger>
</b:Interaction.Triggers>

The actual method:

public async Task OnLoaded()
{
    //other stuff
    if (App.Current.Properties.Contains(nameof(SelectedThing)))
    {
          var selected = JsonConvert.DeserializeObject<SomeType>(App.Current.Properties[nameof(SelectedThing)].ToString());
          SelectedThing = selected;
    }
}

CodePudding user response:

The reason why there is no item selected is because you are setting the SelectedThing source property to a value that's not in the ViewModels source collection.

As you have already discovered, this works better:

var selectedViewModel = ViewModels.Where(x => x.SelectedThing == selected.SelectedThing).FirstOrDefault();
SelectedThing = selectedViewModel;

The item to be selected must be present in the source collection.

  • Related