WPF ListBox и DataTemplates - В чем их сила и как избавиться от стандартного синего маркера выделения?

В очередной раз получил данный вопрос и решил поделиться ответом со всеми.

Как я думаю, многие знают, DataTemplates являются мощнейшим механизмом, позволяющим переопределять визуализацию элементов управления, выводящих множество элементов данных (ListBox, ListView, TreeView...).

С помощью них вы можете выводить в рамках одного визуального шаблона сразу множество аттибутов элемента данных.

Например, имея данный ListBox:

image

Я могу применив данный DataTemplate

    1: <DataTemplate x:Key="EquityTemplate">
    2:             <Grid>
    3:                 <Rectangle Margin="2" >
    4:                     <Rectangle.Fill>
    5:                         <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
    6:                             <LinearGradientBrush.GradientStops>
    7:                                 <GradientStopCollection>
    8:                                     <GradientStop Color="#aaffffff" Offset="0"/>
    9:                                     <GradientStop Color="transparent" Offset="1"/>
   10:                                 </GradientStopCollection>
   11:                             </LinearGradientBrush.GradientStops>
   12:                         </LinearGradientBrush>
   13:                     </Rectangle.Fill>
   14:                 </Rectangle>
   15:                 <Grid x:Name="StackPanel1" Height="29.1333333333334" Margin="5" >
   16:                     <Grid.ColumnDefinitions>
   17:                         <ColumnDefinition Width="40"/>
   18:                         <ColumnDefinition Width="80"/>
   19:                         <ColumnDefinition Width="80"/>
   20:                         <ColumnDefinition Width="160"/>
   21:  
   22:                     </Grid.ColumnDefinitions>
   23:                     <TextBlock FontFamily="Segoe UI"    x:Name="TextBlock1" Grid.Column="1"  Width="Auto"  Text="{Binding Mode=OneWay, Path=FirstName}" Margin="-0.5,0,15.5,12.4666666666666" FontSize="12" FontWeight="Bold" VerticalAlignment="Stretch" Height="Auto"/>
   24:                     <TextBlock  FontFamily="Segoe UI" Margin="0,0,0,0" Width="Auto" Height="16.6666666666668" Grid.Column="1" Grid.ColumnSpan="1" x:Name="TextBlock1_Copy" Text="{Binding Mode=OneWay, Path=LastName}"  d:LayoutOverrides="GridBox" FontSize="10" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" TextTrimming="WordEllipsis"/>
   25:                     <TextBlock  FontFamily="Segoe UI" x:Name="TextBlock2"  Grid.Column="2" Width="60"  Text="{Binding Path=City, Mode=OneWay}" d:LayoutOverrides="None" FontSize="10" VerticalAlignment="Stretch" Margin="8.005,0,11.995,14.466" Height="Auto" Grid.ColumnSpan="1"/>
   26:                     <TextBlock FontFamily="Segoe UI"  d:LayoutOverrides="None" FontSize="10"  FontWeight="Bold" VerticalAlignment="Stretch" Margin="0,14.401,0,0.065" Width="60" Height="Auto" Grid.Column="2" Grid.ColumnSpan="1" x:Name="TextBlock2_Copy" Text="{Binding Mode=OneWay, Path=Region}"  HorizontalAlignment="Center" Background="{x:Null}"/>
   27:                     <TextBlock  FontFamily="Segoe UI" x:Name="TextBlock" Grid.Column="3"  Text="{Binding Mode=OneWay, Path=OrdersCount}" FontSize="10" TextAlignment="Left" FontStyle="Normal" FontWeight="Bold" VerticalAlignment="Bottom" Margin="18.4,0,0,-0.001" Height="15.667" HorizontalAlignment="Stretch"/>
   28:                     <TextBlock Margin="18.4,-2.16,-15.8,14.466" Text="{Binding Mode=OneWay, Path=Address}" TextWrapping="NoWrap" Grid.Column="3" VerticalAlignment="Stretch"/>
   29:  
   30:                     <Image Margin="0,0,10,0" Source="{Binding Path=Photo}" Grid.Column="0"  x:Name="image11" Stretch="Fill" Height="29"  Width="27" />
   31:                 </Grid>
   32:             </Grid>
   33:         </DataTemplate>

превратить его в

image

или применив данный DataTemplate

    1: <DataTemplate x:Key="EquityTemplate">
    2:         <Viewbox>
    3:             <Grid>
    4:                 <Image  Source="{Binding Path=Photo}"></Image>
    5:                 <Grid VerticalAlignment="Bottom" HorizontalAlignment="Stretch"  Height="60" >
    6:                     <Rectangle Margin="0" >
    7:                         <Rectangle.Fill>
    8:                             <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
    9:                                 <LinearGradientBrush.GradientStops>
   10:                                     <GradientStopCollection>
   11:                                         <GradientStop Color="#55000000" Offset="0.001"/>
   12:                                         <GradientStop Color="#FF000000" Offset="1"/>
   13:                                         <GradientStop Color="#96000000" Offset="0.369"/>
   14:                                     </GradientStopCollection>
   15:                                 </LinearGradientBrush.GradientStops>
   16:                             </LinearGradientBrush>
   17:                         </Rectangle.Fill>
   18:                     </Rectangle>
   19:                     <StackPanel Orientation="Vertical">
   20:                         <TextBlock FontWeight="Bold"  FontFamily="Segoe UI" Foreground="#FF80A8FE"    x:Name="TextBlock1"   Width="Auto"  Text="{Binding Mode=OneWay, Path=FirstName}"  FontSize="20"  VerticalAlignment="Stretch" Height="Auto"/>
   21:                         <TextBlock  FontWeight="Bold" FontFamily="Segoe UI" Margin="0,5,0,0" Foreground="#FF80A8FE"  Width="Auto" Height="Auto"   x:Name="TextBlock1_Copy" Text="{Binding Mode=OneWay, Path=LastName}"  d:LayoutOverrides="GridBox" FontSize="20" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" TextTrimming="WordEllipsis"/>
   22:                     </StackPanel>
   23:                 </Grid>
   24:             </Grid>
   25:         </Viewbox>
   26:  
   27:     </DataTemplate>

даже в такой!:

image

И это все просто декларативно, без изменения любой логики ассоциированный с ListBox.

Демонстрация этого примера вживую доступна в моем докладе на TechDays.ru.

Однако, уже несколько раз те, кто применяет DataTemplates, задавали мне вопрос: как избавится от стандартного системного маркера выделения?

В частности мне прислали подобный пример:

image

Кто-то мне рассказывал, что ради этого они сильно помучились и изменяли структуру визуализации ListBox через переопределение Control Template.

На самом деле есть очень простой способ:

На уровне ресурсов конкретного ListBox, или в вышележащих ресурсах, или в ресурсном файле просто делаем цвет выделения прозрачным (Transparent):

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

И все:

image

Наиболее правильно это можно сделать в стиле:

    1: <Style x:Key="listBoxStyle1" TargetType="{x:Type ListBox}">
    2:     <Style.Resources>
    3:         <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
    4:     </Style.Resources>
    5: ...

Таким образом, данное переопределение будет применяться только к ListBox, ассоциированным с данным стилем, а все остальные элементы будут отрабатывать по умолчанию - архив с данным примером прикреплен к посту.

Источник 1, Источник 2

WpfApplication3.zip