Showing posts with label ListBox. Show all posts
Showing posts with label ListBox. Show all posts

Tuesday, January 15, 2013

WPF ListBox Control Style

How to style the WPF ListBox control?

This is actually the continuation of our previous topic WPF ListBox DataTemplate. Please visit it if you're not yet finish reading it.

Below is the target style for our WPF ListBox for this blog.


Styling a WPF ListBox control is not complex and easy to understand. It only depends on you how you style it, but drilling down the template of its Style is very easy.

First we should know how to create a Style object and what properties are we going to modify. In WPF ListBox, during styling, the most important properties to modify are Style (of type Style), ItemContainerStyle (of type Style), and ItemTemplate (of type DataTemplate).

How and what is their usage?

Style: This is a basic property for FrameworkElement when styling a control.

ItemContainerStyle: This is a property for ListBox that is being used when you want to customize the style of each element.

DateTemplate: Mentioned in previous blog, this is used when you want to customize the look of the item in the ListBox (content of the Item as a DataContext). So this vary with the Data Binding.

Style for ItemContainerStyle Property

This is a very simple to implement as we are not drilling or targeting a hierarchical controls like of Grid or Calendar. This mean that you can create your own template in any control. Take a look with a XAML below as the Style for above ListBox ItermContainerStyle property.

<Style x:Key="styleListBoxItem" TargetType="{x:Type ListBoxItem}">
    <Setter Property="OverridesDefaultStyle" Value="True"></Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Grid x:Name="grid">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Border x:Name="hover"
                            Background="#99E7E7E7"
                            BorderBrush="#99979797"
                            BorderThickness="1"
                            CornerRadius="3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            Visibility="Collapsed">
                    </Border>
                    <Border x:Name="highlight"
                            Background="#99B0FFA5"
                            BorderBrush="#995CB74E"
                            BorderThickness="1"
                            CornerRadius="3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            Visibility="Collapsed">
                    </Border>
                    <ContentPresenter></ContentPresenter>
                    <Border Height="1"
                            BorderBrush="#99D7D7D7"
                            BorderThickness="0,1,0,0"
                            Grid.Row="1">
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="hover"
                                Property="Visibility"
                                Value="Visible">
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="highlight"
                                Property="Visibility"
                                Value="Visible">
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

What the XAML written above is very simple. We only created a Style and override the default style of the ListBoxItem. After that, we created our own ControlTemplate to define the areas, texts, UI and design we're going to apply.

We then created a one Grid as the root container since the ControlTemplate cannot contain multiple children. Inside of this Grid control, we created a three Border control that will host the separator line, and highlight and hover event of the user. You will also notice that we place a ContentPresenter object, this will host as the container of the content of the ListBoxItem.

There are triggers written to listen on the events made on the UI. In the event the mouse of the user hovered above the Item in the list box, the written trigger below that checks the IsMouseOver property will command to display the Border with name "hover". In the event the mouse of the user click the item from the list, then the Border with name "highlight" will be displayed as well (trigger that checks the IsSelected property commands it).

Referencing the Styles

In the case you completed your own style for ItemContainerStyle property, then you need to create another Style that applies the ItemContanerStyle you'd created earlier into the ListBox control. Below's snippet is the sample (text with yellow background is the application).

<Style x:Key="styleListBox" TargetType="{x:Type ListBox}">
    <Setter Property="OverridesDefaultStyle" Value="True"></Setter>
    <Setter Property="ItemContainerStyle" Value="{StaticResource ResourceKey=styleListBoxItem}"></Setter>
    <Setter Property="ItemTemplate" Value="{StaticResource ResourceKey=templateListBoxItem}"></Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <Border BorderBrush="#5A5A5A" BorderThickness="1" CornerRadius="4">
                    <ScrollViewer Margin="1">
                        <ItemsPresenter Margin="1"></ItemsPresenter>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

You can follow WPF ListBox DateTemplate blog of how to apply the actual Style in the ListBox control.

And that's it. We just finish the blog for ListBox. Please visit other blog for your reference.

Monday, January 14, 2013

WPF ListBox Control DataTemplate

How to modify a WPF ListBox control template?

The WPF ListBox control is a simple list type view control that enumerates all the items from the items source and display it in the User Interface. This is a one way to simplify the display of multiple items with dynamic capability.

Below shows the actual WPF ListBox control (default style and template) inside a window.



You'll see the control displayed 7 items (company name) since I actually pre-loaded the item source of the control. In order for you not to confuse, I'll explain the classes I used in binding and how did I loaded the items into the ListBox.

Image below is my current solution. I added a new folder that contains a logo for the company listed above and set each item Build Action property to be a Resource.



In my ListBox Window, I added the code below.


<Window x:Class="CodesDirectory.ListBox"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ListBox" Height="300" Width="300">
    <Grid>
        <ListBox Name="listBox" DisplayMemberPath="Name" Margin="5"></ListBox>
    </Grid>
</Window>


In my Window code behind, below is the code.


public ListBox()
{
    InitializeComponent();
    this.LoadLogos();
}


private void LoadLogos()
{
    this.listBox.Items.Add(new CompanyDataContext("Adobe", "Adobe is a designing tool.", "/Company Logos/adobe.jpg"));
    this.listBox.Items.Add(new CompanyDataContext("Facebook", "FedEx is a social networking website.", "/Company Logos/facebook.jpg"));
    this.listBox.Items.Add(new CompanyDataContext("FedEx", "FedEx is a courier company.", "/Company Logos/fedex.jpg"));
    this.listBox.Items.Add(new CompanyDataContext("Golden Gate", "Golden gate is a financial company focusing on stock exchange.", "/Company Logos/golden gate.jpg"));
    this.listBox.Items.Add(new CompanyDataContext("Onitsuka Tiger", "A shoe company originated from Japan.", "/Company Logos/onitsuka tiger.jpg"));
    this.listBox.Items.Add(new CompanyDataContext("Twitter", "Twitter is a micro blogging website.", "/Company Logos/twitter.jpg"));
    this.listBox.Items.Add(new CompanyDataContext("Vans", "Vans is a shoe company for the skaters.", "/Company Logos/vans.jpg"));
}

Now, what is the CompanyDataContext object? It is a custom Type I made to host the values I want to be displayed in the ListBox. In short, this is a DataContext. Once you added this object manually into the ListBox  then each item you see in the ListBox is now a CompanyDataContext object (you can cast and get the property everytime you iterate or reference it).

Note: One important property in ListBox when you're binding an object is DisplayMemberPath. This define what field of the object are you going to display in every item visible in the ListBox .

Below is the actual class.


private class CompanyDataContext
{
    public CompanyDataContext(string name, string about, string image)
    {
        this.Name = name;
        this.About = about;
        this.Image = image;
    }

    public string Name { get; private set; }

    public string About { get; private set; }

    public string Image { get; private set; }
}

Now since I already defined the basic needs, let us go to templating part.

Customize WPF ListBox control template

One important property you need to do when styling is the ItemContainerStyle property of the ListBox control. This property is used when designing each of the item of the ListBox, or how are you going to customized the display of each item.

Another property that is common in used is the DateTemplate. This property is used how are you going to override the existing template used by the default ListBoxItem style when binding a data object. This is usable when you only would like to override the Template and not the Style.

In my case, I will only use the DataTemplate and later will discuss how to modify the actual style.



Image above only used the DataTemplate to design how are you going to display the individual item in the ListBox control. To implement this, you need to create a new ResourceDictionary object and reference it to your Window (or the parent container of your ListBox).

Sample ResourceDictionary for the ListBox.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   
    <DataTemplate x:Key="templateListBoxItem">
        <Grid Margin="5">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Border Grid.Column="0"
                    Grid.Row="0"
                    Grid.RowSpan="2"
                    Margin="0,0,10,0">
                <Image Source="{Binding Path=Image}"
                       Stretch="Fill"
                       Height="40"
                       Width="40"></Image>
            </Border>
            <TextBlock Text="{Binding Path=Name}"
                       FontWeight="Bold"
                       Grid.Column="1"
                       Grid.Row="0"></TextBlock>
            <TextBlock Text="{Binding Path=About}"
                       Grid.Column="1"
                       Grid.Row="1"></TextBlock>
        </Grid>
    </DataTemplate>
   
    <Style x:Key="styleListBox" TargetType="{x:Type ListBox}">
        <Setter Property="ItemTemplate" Value="{StaticResource ResourceKey=templateListBoxItem}"></Setter>
    </Style>

</ResourceDictionary>

Above ResourceDictionary object only contains the data template named templateListBoxItem and a style named styleListBox. Reference and apply it to your ListBox.

Go back to your ListBox window and add this at the top.


<Window.Resources>
     <ResourceDictionary Source="/Styles/ListBox.xaml"></ResourceDictionary>
</Window.Resources>

Once added, set the style of your ListBox by using the DynamicResource binding.

<ListBox Name="listBox"
         DisplayMemberPath="Name"
         Margin="5"
         Style="{DynamicResource ResourceKey=styleListBox}">
</ListBox>

And that's it. Please visit this link how to modify the ListBox style.