Dejan Maksimovic
Dejan Maksimovic

Reputation: 507

Unfocused ListBox, item style

OK, I can't believe there is no online resources about this. I want to do a simple thing and change style of a ListBox item when it's selected and it's parent ListBox has lost focus.

We have been using VisualStateManager for this purpose, but since there is overlapping in Selected, SelectedFocused and Focused states, there were some bugs introduced when selecting items holding ctrl for example(wrong items appear selected). I decided to fix it using Triggers and found out that there seems to be no way of triggering when ListBox lost focus.

My question is what is the right way of implementing this behavior, and please don't say "override SystemColors"...

EDIT:

OK, I have up-voted both answers but picked Viv's response because his answer makes it work exactly like original ListBox while I don't have problems with mouse-over and other styles I already use. I have already seen usage of Selector attached property, but never tried IsSelectionActive, it worked like a charm. I would recommend going for triggers for this type of problem, although the VisualStateManager is newer in WPF. I think there are clearly some problems with overlapping states that can be avoided.

Thanks again to Viv and Richard for providing great examples of 2 ways of implementing the solution for my problem.

Upvotes: 2

Views: 2612

Answers (2)

Viv
Viv

Reputation: 17398

OK, I can't believe there is no online resources about this. I want to do a simple thing and change style of a ListBox item when it's selected and it's parent ListBox has lost focus.

guess your looking for a MultiTrigger with IsSelected=true and Selector.IsSelectionActive=false?

so something like:

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <ListBox Margin="15">
    <ListBox.ItemContainerStyle>
      <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Foreground"
                Value="Blue" />
        <Style.Triggers>
          <MultiTrigger>
            <MultiTrigger.Conditions>
              <Condition Property="IsSelected"
                          Value="true" />
              <Condition Property="Selector.IsSelectionActive"
                          Value="false" />
            </MultiTrigger.Conditions>
            <Setter Property="Foreground"
                    Value="Red" />
          </MultiTrigger>
        </Style.Triggers>
      </Style>
    </ListBox.ItemContainerStyle>
    <ListBoxItem Content="A" />
    <ListBoxItem Content="B" />
    <ListBoxItem Content="C" />
  </ListBox>
  <ListBox Grid.Column="1"
            Margin="15">
    <ListBoxItem Content="A" />
    <ListBoxItem Content="B" />
    <ListBoxItem Content="C" />
  </ListBox>
</Grid>

Now when an item in the left ListBox is selected and then if the actual ListBox looses focus, it would get a Red Foreground like:

enter image description here

Foreground is just an example, using the MultiTrigger you can tweak the Style as you see fit.

Upvotes: 6

Richard E
Richard E

Reputation: 4939

Here is a Style for the ListBoxItem that used the VisualStateManager. It highlights the items in the manner that I would expect.

  <Style TargetType="ListBoxItem">
        <Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Border x:Name="Border"
                            Background="Transparent"
                            CornerRadius="3"
                            BorderThickness="1"
                            Padding="2">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="SelectionStates">
                                <VisualState x:Name="Unselected"/>
                                <VisualState x:Name="Selected">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                        Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                            <EasingColorKeyFrame KeyTime="0"
                                                                 Value="DodgerBlue"/>
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="SelectedUnfocused">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                        Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                            <EasingColorKeyFrame KeyTime="0"
                                                                 Value="CornflowerBlue"/>
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Upvotes: 3

Related Questions