Hi,
in these days I needed to override the default highlight color used for marking selected items in GridView of WPF Application running on Windows 7.
First of all I noticed that the well known strategy that consist in overriding the SystemColors.HighlightBrushKey didn’t work for ListView that contains GridView on Windows 7 even if the same strategy works fine in ListBox and ListView (that does not have GridView inside) on both Windows XP and 7. This strange behavior is also described in the following msdn post: http://social.msdn.microsoft.com/Forums/en/wpf/thread/1f62b66f-bdcb-4092-8568-a8fa4d39ea9b.

In order to solve that problem, my idea was to define a global style for ListViewItem, but ListViewItem Style  must be different for ListView that contains GridView and ListView without GridView.
In fact when a ListView contains a GridView, the ListViewItem Style must display items via GridViewRowPresenter.
Instead when ListView does not contains the GridView, the ListViewItem Style must display item via ContentPresenter.
This implies to implement a Trigger into ListViewItem Style in order to hide\show the GridViewRowPresenter or the ContentPresenter.

Below a screenshot of ListView and ListView + GridView using a common ListViewItem Style! The solution is downloadable here.

Highlighted item in ListView via ListViewItem Style

And here you are the final working solution for defining a common ListViewItem Style. Notice the Triggers in lines 36-38 that shows/hides the ContentPresenter.

        <Style TargetType="{x:Type ListViewItem}" x:Key="{x:Type ListViewItem}" >
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="UIElement.SnapsToDevicePixels" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListViewItem}">

                        <Border SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            BorderBrush="{TemplateBinding BorderBrush}"
                            Background="{TemplateBinding Background}">

                            <Grid>

                                <!-- This is used when GridView is put inside the ListView -->
                                <GridViewRowPresenter Content="{TemplateBinding ContentControl.Content}"
                                                  HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" 
                                                  VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
                                                  SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>

                                <!-- This is used for ListView that does not use GridView -->
                                <ContentPresenter x:Name="contentPresenter"
                                              Content="{TemplateBinding ContentControl.Content}" 
                                              Visibility="Collapsed"
                                              ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" 
                                              ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" 
                                              HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" 
                                              VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
                                              SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
                            </Grid>

                        </Border>

                        <ControlTemplate.Triggers>
                            <Trigger Property="GridView.ColumnCollection" Value="{x:Null}">
                                <Setter TargetName="contentPresenter" Property="Visibility" Value="Visible"/>
                            </Trigger>

                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Background" Value="#FFB3D0E5" />
                            </Trigger>

                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                            </Trigger>
                        </ControlTemplate.Triggers>

                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Stay tuned!
Marzio.


What you have to do for specifying a background color for highlighting an item of a ListView is simply add to your <ListView.Resources> the following SolidColorBrush:

        <ListView ScrollViewer.VerticalScrollBarVisibility="Visible"
                  x:Name="myListView"
                  ItemsSource="{Binding Path=myFileCollection}">

            <ListView.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                                 Color="OrangeRed"/>
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                                 Color="Orange"/>
            </ListView.Resources>

        </ListView>

The first SolidColorBrush overrides the Windoes Highlight Brush for indicating a selected item having the focus. The second SolidColorBrush is used for overriding the default Windows Brush used for indicating a selected item that doesn’t have a focus.


Hi guys!
Today I am going to explain how completely customizing a WPF ListView in your applications using an XML configuration File.

The Source File in VS2008 is available HERE .

The Sample Application

The Application I developed simply displays a list of Files describing the name, the extension and the size. The amazing feature is that the displayed columns and the individual styles of columns are configurable from an xml file!
The Application looks like the following:

application
And here you can take a look at the configuration file:

xml-file
As you can see all the displayed columns are configured into the XML file and for each columns the Style to be used is configured as well. The xml file describes the following configuration:  the FileName displayed in an editable TextBox, the FileExtension displayed as text, the KBSize displayed as text as well, the FileExtension again but displayed with icons, the KBSize again but displayed with a green circle for smaller files and displayed with a red circle for largest files.

How To

In the next sections are described the steps for building the Sample Application.

1. Deserializing the XML File (using XSD.EXE tool)

In order to develop the application as fast as possible I used the xsd.exe tool which is capable to automatically generate a C# source file from an xsd schema. The source file generated is able to represent an xml file content conform to the described schema file.
The xsd schema describing the configuration file we want is the following:

<xs:schema xmlns:mstns="http://tempuri.org/MyCustomizedColumns.xsd"
           elementFormDefault="qualified"
           targetNamespace="http://tempuri.org/MyCustomizedColumns.xsd"
           id="MyCustomizedColumns"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:simpleType name="CellStyles">
    <xs:restriction base="xs:string">
      <xs:enumeration value="SimplePlainText" />
      <xs:enumeration value="HyperLinkText" />
      <xs:enumeration value="EditableTextBox" />
      <xs:enumeration value="KBSizeIcon" />
      <xs:enumeration value="IconFileType" />
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Columns">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Summary" />
      <xs:enumeration value="FileName" />
      <xs:enumeration value="KBSize" />
      <xs:enumeration value="FileExtension" />
    </xs:restriction>
  </xs:simpleType>

  <xs:complexType name="ColumnDefinition">
    <xs:attribute name="Column" type="mstns:Columns" use="required" />
    <xs:attribute name="CellStyle" type="mstns:CellStyles" use="required" />
  </xs:complexType>

  <xs:element name="ColumnsDefinitions">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0"
                    maxOccurs="unbounded"
                    name="ColumnDefinition"
                    type="mstns:ColumnDefinition" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

The above xsd schema describes two simple types: the CellStyles and the Columns which are enumerations describing the possibles columns and the possibles styles. Then the schema definins the ColumnDefinition complexType which describes a column type and its relevant style. At the end of the schema the element ColumnsDefinitions defines a sequence of ColumnDefinition types representing the entire ListView customization.

The following few lines of code are able to reading any xml files that are conformed to the xml schema. Here an XmlReaderSettings object is created and is configured for validating any xml file conformed to the above schema. After that the XmlSerializer object is created and used for deserializing the xml file. The xml content is put into the ColumnsDefinitions object which is defined into the automatically generated file.

        private ColumnsDefinitions ReadConfiguredColumns()
        {
            try
            {
                bool o = File.Exists("ColumnsConfiguration.xml");
                using (FileStream xmlConfigStream = File.OpenRead("ColumnsConfiguration.xml"),
                                  xmlSchemaStream = File.OpenRead("MyCustomizedColumns.xsd"))
                {
                    XmlSchemaSet schemaSet = new XmlSchemaSet();
                    XmlReader schemaReader = XmlReader.Create(xmlSchemaStream);
                    schemaSet.Add(@"http://tempuri.org/MyCustomizedColumns.xsd", schemaReader);

                    XmlReaderSettings settings = new XmlReaderSettings();
                    settings.ValidationType = ValidationType.Schema;
                    settings.IgnoreWhitespace = true;
                    settings.IgnoreComments = true;
                    settings.Schemas = schemaSet;

                    XmlReader reader = XmlReader.Create(xmlConfigStream, settings);

                    XmlSerializer xs = new XmlSerializer(typeof(ColumnsDefinitions));
                    ColumnsDefinitions configuredColumns = xs.Deserialize(reader) as ColumnsDefinitions;
                    return configuredColumns;
                }
            }
            catch (Exception) { return null; }
        }

2. The FileItem Class

Just for simplifying the reading of the subsequent sections, here is the code of the FileItem class. I choose the FileItem to inherit from the DependencyObject in order to enables animation, styling, binding, and so on in the easier way.

C# File Item

3. The Xaml Sample Application Code (ResourceDictionary, Styles and Binding Rock!)

The xaml code consists into two parts: the first one is contained into Windows.Resources and defines the same styles defined into the above xsd schema, the other one is the ListView itself simply containing a GridView that is used in codebehind for building columns and applying relevant styles (as described in the last section).

Xaml Resources ListView GridView
In the above code is displayed the SimplePlainTextStyle, which can be applied to a ContentControl and simply displays the ContentControl Content. In other words the <ContentPresenter/> means: “here is displayed the Content of the ContentControl, regardless the Content type is”. The ContentControl Content can be whatever you want, even if in our case the simply a string, as I’m going to explain.
Instead the HyperLinkText style displays an hyperlink text but it is  very closed to the SimplePlainTextStyle.
The EditableTextBox style works like the above styles but it is defined in the following way:

            <Style x:Key="EditableTextBox"
                     TargetType="{x:Type ContentControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ContentControl}">
                            <Grid Margin="5"
                                  VerticalAlignment="Top" >
                                <TextBox Text="{TemplateBinding Property=Content}"/>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

Because there are any way to write something like <TextBox…> <ContentPresenter/> </TextBox>, the only way to display the content into the TextBox is to write <TextBox Text=”{TemplateBinding Property=Content}”/>.  This means: “the Text to be displayed is the same displayed into the Content Property of the above Template. The above template is aContentControl Template, because the TargetType of our Style is the ContentControl”.
The KBSizeIcon and the IconFileType Styles are different from the above styles because these are specific styles that can be applied only to specific columns. What I mean is: a SimplePlainTextStyle can be applied to the FileSize or to the FileName or the FileExtensio as well, while the KBSizeIcon style can be applied only to the KBSize column, as well as it makes any sense to apply the IconFileType style to columns different from the FileExtension column!  Because these styles are specifics, they are directly binded to specifics properties of the FileItem object.  The following image displays the xaml code describing the KBSizeIcon:

            <Style x:Key="KBSizeIcon"
                     TargetType="{x:Type ContentControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ContentControl}">
                            <Grid Margin="5"
                                  VerticalAlignment="Top" >
                                <Border x:Name="myborder" Width="12" Height="12" Background="{x:Null}"
                                        CornerRadius="12" BorderThickness="0">
                                </Border>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <DataTrigger Binding="{Binding Path=IsBiggerFile}"
                                                             Value="True">
                                    <Setter TargetName="myborder" Property="Background" Value="Red"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Path=IsBiggerFile}"
                                                             Value="False">
                                    <Setter TargetName="myborder" Property="Background" Value="Green"/>
                                </DataTrigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>

                    </Setter.Value>
                </Setter>
            </Style>

As you can see the displayed icon (green or red) is choosen using ControlTemplate.Triggers that are binded to IsBiggerFile FileItem Dependency Property.

4. The C# Code for building Customized Columns (Factory pattern Rock!)

Finally the engine code that is able to building the columns and applying the styles:

        private void CreateCostumizedColumns(ColumnsDefinitions configuredColumns)
        {
            foreach (ColumnDefinition col in configuredColumns.ColumnDefinition)
            {
                GridViewColumn gridColumn = new GridViewColumn();

                FrameworkElementFactory contentControlFactory =
                                            new FrameworkElementFactory(typeof(ContentControl));
                Style confStyle = this.FindResource(col.CellStyle.ToString()) as Style;
                contentControlFactory.SetValue(ContentControl.StyleProperty, confStyle);

                if (col.CellStyle != CellStyles.KBSizeIcon &&
                    col.CellStyle != CellStyles.IconFileType)
                {
                    Binding binding = new Binding(col.Column.ToString());
                    contentControlFactory.SetBinding(ContentControl.ContentProperty, binding);
                }

                gridColumn.Header = col.Column.ToString();
                gridColumn.CellTemplate = new DataTemplate();
                gridColumn.CellTemplate.VisualTree = contentControlFactory;

                myGridView.Columns.Add(gridColumn);
            }
        }

The code explains itself in an easy way. For each column described into the configuration xml file, a new GridColumn is created. Using  the FrameworkElementFactory we are able create a “factory” that, in our code,  is an object able to build ContentControls object. The configured Style is associated to the contentControlFactory object and than, if the style we are applying is not a “specific style” (I mean it is not KBSizeIcon or IconFileType), we set a binding between the Content Property of the ContentControl and the relevant FileItem Dependency Property. Finally the Column Header is set, a new DataTemplate is created and assigned to the column CellTemplate property, the VisualTree CellTemplate is associated to the contentControlFactory and the new column is added to the GridView.

Follow

Get every new post delivered to your Inbox.