Specifying the Selection Color, Content Alignment, and Background Color for items in a ListBox


This post covers some tips and tricks that people frequently ask concerning specifying the appearance of a ListBox.  Here’s some things that someone, somewhere, might find useful:


 


Specifying the Selection Color


 


If you’ve ever tried the following, you know it won’t work.


 


      <Style TargetType=”ListBoxItem”>


        <Style.Triggers>


          <Trigger Property=”IsSelected” Value=”True”>


            <Setter Property=”Background” Value=”LightGreen” />


          </Trigger>


        </Style.Triggers>


      </Style>


 


This doesn’t work because the control template of the ListBoxItem changes the background of an Border that is internal to the template, not the background of the ListBoxItem itself. The control template uses the color defined by SystemColors.HighlightBrush.  Luckily, the SystemColors.HighlightBrush has a key associated with it, so you can create a Brush with its key set to SystemColors.HighlightBrushKey to change the color of a selected ListBoxItem:


 


      <Style TargetType=”ListBoxItem”>


        <Style.Resources>


          <SolidColorBrush x:Key=”{x:Static SystemColors.HighlightBrushKey}” Color=”LightGreen”/>


        </Style.Resources>


      </Style>


 


You might be thinking, “That’s great, but when the control loses focus, the selection still turns to the default color (usually gray).”  Never fear, the background for selected items in an inactive ListBox is specified by SystemColors.ControlBrush and you can use the SystemColors.ControlBrushKey to specify a different color. The following style causes the select items in a ListBox to be LightGreen when the ListBox has focus and LightBlue when it doesn’t have focus.


 


      <Style TargetType=”ListBoxItem”>


        <Style.Resources>


          <SolidColorBrush x:Key=”{x:Static SystemColors.HighlightBrushKey}” Color=”LightGreen”/>


          <SolidColorBrush x:Key=”{x:Static SystemColors.ControlBrushKey}” Color=”LightBlue”/>


        </Style.Resources>


      </Style>


 


Aligning Content in a ListBox


 


Often you want the content of a ListBox to horizontally span the row. The Data Templating Overview discusses this, but it comes up frequently so it bears repeating.  Suppose your ListBox is bound to a list of items to purchase.  Perhaps you want the name of the item on the left and the price of the item below the name and to the far right.  Your data template might look like this:


 


        <DataTemplate>


          <Grid>


 


            <Grid.RowDefinitions>


              <RowDefinition/>


              <RowDefinition/>


            </Grid.RowDefinitions>


 


            <TextBlock Text=”{Binding XPath=@name}”/>


            <TextBlock Text=”{Binding XPath=@price}”


                       Grid.Row=”1″ HorizontalAlignment=”Right”/>


          </Grid>


        </DataTemplate>


 


This gives you the following:


 


 



 


As you can see, the TextBlock for the price is right-aligned, but it isn’t aligned with the edge of the ListBox.  This is because the TextBlock is right-aligned with the Grid in the DataTemplate and the Grid sizes to its content   To have the Grid span the width of the ListBox.  Set the ListBox.HorizontalContentAlignment property to Stretch. Then the price will align to the right edge of the ListBox.


 


 



 


Making the Background Span the Entire Row


 


Setting the ListBox.HorizontalContentAlignment property to Stretch also allows the Background brush to paint the entire row of a ListBox. Suppose you want to bind the Background to a data source or use a data trigger to change the background of an item.  The following data template changes the background on an item to red if it is sold.


 


        <DataTemplate>


            <Grid Name=”grid1″ Background=”LightGreen”>


            


              <Grid.RowDefinitions>


                <RowDefinition/>


                <RowDefinition/>


              </Grid.RowDefinitions>


             


              <TextBlock Text=”{Binding XPath=@name}”/>


              <TextBlock Grid.Row=”1″


                         Text=”{Binding XPath=@price}”/>


            </Grid>


 


 


          <DataTemplate.Triggers>


            <DataTrigger Binding=”{Binding XPath=@sold}” Value=”true”>


              <Setter TargetName=”grid1″ Property=”Background” Value=”Red”/>


            </DataTrigger>


          </DataTemplate.Triggers>


 


        </DataTemplate>


 


If you don’t set the HorizontalContentAlignmentProperty, the ListBox looks likes the following:


 


 


 


That’s probably not what you want.  When ListBox.HorizontalContentAlignment equals to Stretch, the background paints the entire row.


 


 


Comments (10)

  1. Jan Kučera says:

    Hello, useful tips, indeed.

    However, when you set the HighlightBrushKey to the Transparent or some light color, it is likely you also wan’t to change the text color. What’s the key here? 😉

    Second, if I just want to turn off such highlighting, is there any better way then setting HighlightBrushKey and ControlBrushKey to Transparent?

    Thanks, Jan.

  2. wcsdkteam says:

    Hi Jan,

    Good questions.  Regarding the foreground, the following keys are used:

    Key when the ListBox has focus: SystemColors.HighlightTextBrushKey

    Key when the ListBox does not have focus: SystemColors.ControlTextBrushKey

    But the ListBoxItem control template changes the Foreground property of the ListBoxItem, so you can also just use a Trigger to change the color of the Foreground.

         <Style TargetType="ListBoxItem">

           <Style.Resources>

             <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightGreen"/>

             <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="LightBlue"/>

           </Style.Resources>

           <Style.Triggers>

             <Trigger Property="IsSelected" Value="True">

               <Setter Property="Foreground" Value="Red" />

             </Trigger>

           </Style.Triggers>

         </Style>

    To turn of highlighting, I believe using the Transparent brush is easiest.  Another option is to redefine the control tenplate of the ListBoxItem and remove the triggers for IsSelected.  Here’s the ControlTemplate defined in WPF.  I’ve marked which triggers should be removed to disable selection highlighting.

                   <ControlTemplate TargetType="{x:Type ListBoxItem}">

                       <Border Name="Bd"

                               Background="{TemplateBinding Background}"

                               BorderBrush="{TemplateBinding BorderBrush}"

                               BorderThickness="{TemplateBinding BorderThickness}"

                               Padding="{TemplateBinding Padding}"

                               SnapsToDevicePixels="true">

                           <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"

                                             VerticalAlignment="{TemplateBinding VerticalContentAlignment}"

                                             SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>

                       </Border>

                       <ControlTemplate.Triggers>

                           <!–***REMOVE THIS TRIGGER**–>

                           <Trigger Property="IsSelected"

                                    Value="true">

                               <Setter TargetName="Bd"

                                       Property="Background"

                                       Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>

                               <Setter Property="Foreground"

                                       Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>

                           </Trigger>

                           <!–***REMOVE THIS TRIGGER**–>

                           <MultiTrigger>

                               <MultiTrigger.Conditions>

                                   <Condition Property="IsSelected"

                                              Value="true"/>

                                   <Condition Property="Selector.IsSelectionActive"

                                              Value="false"/>

                               </MultiTrigger.Conditions>

                               <Setter TargetName="Bd"

                                       Property="Background"

                                       Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>

                               <Setter Property="Foreground

                                       Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>

                           </MultiTrigger>

                           <Trigger Property="IsEnabled"

                                    Value="false">

                               <Setter Property="Foreground"

                                       Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>

                           </Trigger>

                       </ControlTemplate.Triggers>

                   </ControlTemplate>

    Note that you could also redefine the LlistBoxItem ControlTemplate to change the color of the background of the ListBoxItem by changing the Values in the setters above…but the point of the post was to show how change the color without having to redefine the ControlTemplate.

  3. Setting the Selection Color for a list box item in WPF

  4. В очередной раз получил данный вопрос и решил поделиться ответом со всеми. &#160; Как я думаю, многие

  5. Jan Kučera says:

    Hello again!

    Could this trick be used to replace one brush with another? I’m trying to implement HideSelection=False on a ListBox. The easiest I could come up with is:

    <Style.Resources>

       <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{x:Static SystemColors.HighlightColor}" />

    </Style.Resources>

    But this creates solid brush even if HighlightBrush wasn’t solid. Is there any way how to do this while preserving the whole brush type and its properties?

    Thanks!

    Jan

  6. Carole Snyder says:

    Hi Jan,

    Sorry for the delay in getting back to you.  If I undersstand your question, in some place the ControlBrush is used, but you want the HighlightBrush to be used instead.  Basically, you want a copy of the HighlightBrush and give it the key ControlBrushKey.  There isn’t a way to do this.  In this case, you have to copy the control template and change the references from the ControlBrush to the HighlightBrush.  Sorry I don’t have better news for you.

    Carole

  7. Jan Kučera says:

    Hi Carole,

    Yes you understand the question well. So it’s basically a choice whether to lock brush type or listbox template from being updated with future framework updates. I guess that fixing the brush type to solid is a bit better choice. Anyway, thank you for your response! At least I know I don’t miss anything.

    Jan

  8. smercer says:

    The color keys are useful, but there’s still one more color involved in selection — the color of the dotted line around the perimeter of the selected item.

    a) What is the name of the key for that color?

    b) How do you find a list of all the keys used by a given control?

  9. donny says:

    This is a really great tip. But if I don’t work for Microsoft how exactly was I suppose to know how to do this?

  10. Carole Snyder says:

    Hi Donny,

    Thanks for your feedback.  You’re right, this is a tricky problem.  Were you expecting to find this information on MSDN, or is there another way you would have liked to have found this information?    We do sometimes publish tips and tricks on our blog that aren’t in our official documentation, because blogs are sometimes so much easier to produce.  We’d love to hear more about what you meant.  

    Thanks,

    Carole