Saturday, 23 March 2013

Part - 5: Applying style to ListBox, Continued

This post is the fifth in the series of ListBox control. Here is the reference of all the posts in this series for quick reference.

Part - 1: ListBox basics - Adding Items manually to ListBox and understanding properties of ListBox

Part - 2: Data Binding in ListBox (Binding ListBox to data source)

Part - 3: Binding ListBox to XML

Part - 4: Applying style to ListBox

Part - 5: Applying style to ListBox, Continued

Part - 6: ListBox custom ControlTemplate

 

In last post, we learned basic structure of ListBox control and a sample of how our ListBox control would look after applying basic style. In post 3, we have see how we can DataBind ListBox control. In this post we continue using same sample and apply style to different layers of ListBox control step by step.

ListBox DataBinding

A simple class “Fruit” to hold fruit information.

public class Fruit
{
public string Name { get; set; }
public string ImagePath { get; set; }
public Int32 Calories { get; set; }
public string Vitamins { get; set; }
}


Add simple ListBox control to XAML

<ListBox Name="lstFruits" DisplayMemberPath="Name"></ListBox>


In code behind (constructor), Create a list of Fruits and bind to ListBox control.

List<Fruit> myFruits = new List<Fruit>()
{
new Fruit() { Name = "Apple", ImagePath = "Images\\Apple.png", Calories = 61, Vitamins = "A,C" },
new Fruit() { Name = "Orange", ImagePath = "Images\\Orange.png", Calories = 51, Vitamins = "A,B1,C" },
new Fruit() { Name = "Grape", ImagePath = "Images\\Grapes.png", Calories = 40, Vitamins = "C" },
new Fruit() { Name = "Mango", ImagePath = "Images\\Mango.png", Calories = 80, Vitamins = "A,B1,C" }
};

lstFruits.ItemsSource = myFruits;


ItemSource property can be bound to any data source that implements IEnumerable. Generic List is one of them that implements IEnumerable.



Output:



 


1. Apply style to ListBox control

<Window x:Class="ListboxSample.ListBoxBasicStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxBasicStyle" Height="400" Width="400" FontFamily="Verdana" FontSize="13">
<Window.Resources>
<Style x:Key="ListBoxBlueStyle" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="#94B4D0"></Setter>
<Setter Property="Foreground" Value="#253E53"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="Padding" Value="5"></Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox Name="lstFruits" DisplayMemberPath="Name" Style="{StaticResource ResourceKey=ListBoxBlueStyle}">
</ListBox>
</Grid>
</Window>

Output:



Understanding XAML



We have added a ListBox control with list of static items.



We have added a style in window resources section, provided unique key to style that will be used to refer style later and set target type to ListBox control.


We have applied some properties directly on ListBox control.


2. Apply style to each ListBoxItem (ItemContainer)


In above style, If we see individual items in ListBox control still remain same and needs some formatting to display better. So we use ItemContainer to apply style to each ListBoxItem. One point to note here is that we are applying style to ItemContainer of each individual item and not the items itself.

<Style x:Key="ListBoxBlueStyle" TargetType="{x:Type ListBox}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#B5E37D" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="#253E53" />
</Style.Resources>
<Setter Property="Background" Value="#94B4D0"></Setter>
<Setter Property="Foreground" Value="#253E53"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="Padding" Value="5"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="#F5F5F5"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="Margin" Value="4"></Setter>
<Setter Property="Padding" Value="8"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Normal"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>

Output


ListBox custom style


Understanding XAML



ItemContainerStyle property is used to set style for each individual ListBoxItem. Here we create a new style with target type as ListBoxItem. In style we apply some basic properties on each item.


Triggers: Triggers is very handy feature in WPF to provide conditional formatting. Here, If mouse is moved over individual item then we set font weight to bold to provide a visual feedback. If item is in normal state or selected state then font weight is normal.


Small Hack


If we see the sample image at the start of post, it can be observed that selected item in ListBox has Green background. If we set Background property in “IsSelected” Trigger of ListBoxItem style then this will not work. Because ListBox control default template has Background of each ListBoxItem set to system color and can not be changed. So here is the small hack. We override system color for this particular ListBox style in resources section. Hence it will not have any effect on other controls and styles except this one


3. Changing default ItemsPanel


By default, ItemsPanel to hold items in ListBox control is VirtualizingStackPanel which arranges controls vertically. We can change the default panel to any control that derives from Panel like StackPanel, DockPanel, WrapPanel and so on.


In this example, we change the default panel to WrapPanel.

<Style x:Key="ListBoxBlueStyle" TargetType="{x:Type ListBox}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#B5E37D" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="#253E53" />
</Style.Resources>
<Setter Property="Background" Value="#94B4D0"></Setter>
<Setter Property="Foreground" Value="#253E53"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="Padding" Value="5"></Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Width" Value="100"></Setter>
<Setter Property="Height" Value="100"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
<Setter Property="Background" Value="#F5F5F5"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="Margin" Value="4"></Setter>
<Setter Property="Padding" Value="8"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Normal"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel></WrapPanel>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>

Output


ListBox custom style


Understanding XAML



We set ItemsPanel property to new template which has WrapPanel.


We have set one additional property to ListBox control ScrollViewer.HorizonalScrollBarVisibility to Hidden so that content will wrap automatically when there is no space left in horizontal direction.


We also set few other properties to ListBoxitem style like Width, Height and HorizontalContentAlignment to get the desired look and feel


4. Applying DataTemplate to each item


We have not yet touched on layer which is the actual data/content of each item in ListBox control. We can create a new DataTemplate and apply to data items in ListBox. DataTemplate is powerful feature of WPF that defines what and how to display data in control.

<Style x:Key="ListBoxBlueStyle" TargetType="{x:Type ListBox}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#B5E37D" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="#253E53" />
</Style.Resources>
<Setter Property="Background" Value="#94B4D0"></Setter>
<Setter Property="Foreground" Value="#253E53"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="Padding" Value="5"></Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Width" Value="100"></Setter>
<Setter Property="Height" Value="100"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
<Setter Property="Background" Value="#F5F5F5"></Setter>
<Setter Property="BorderBrush" Value="#497CA5"></Setter>
<Setter Property="Margin" Value="4"></Setter>
<Setter Property="Padding" Value="8"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Normal"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel></WrapPanel>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel LastChildFill="True">
<TextBlock Text="{Binding Path=Name}" DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="5"></TextBlock>
<Image Source="{Binding Path=ImagePath}"></Image>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<ListBox Name="lstFruits" Style="{StaticResource ResourceKey=ListBoxBlueStyle}"></ListBox>

Output


ListBox custom style


Understanding XAML


ItemTemplate property of ListBox control can be used to apply new DataTemplate. Inside setter we created a new DataTemplate that would be applied to each data item in ListBox. Till now we have used DisplayMemberPath property in ListBox control to specify what data (from Fruit class) would be displayed in ListBox items. In DisplayMemberPath, we could specify only single property of fruit class to be displayed. But DataTemplate provides flexibility to define what and how data items would be displayed. Here, We choose to display 2 properties Name and Image of fruit class. Moreover we have DockPanel that defines how this data would be displayed. Image is displayed at the top and Name at bottom.

Wednesday, 13 March 2013

Part - 4: Applying style to ListBox control

This post is the fourth in the series of ListBox control. Here is the reference of all the posts in this series for quick reference.

Part - 1: ListBox basics - Adding Items manually to ListBox and understanding properties of ListBox

Part - 2: Data Binding in ListBox (Binding ListBox to data source)

Part - 3: Binding ListBox to XML

Part - 4: Applying style to ListBox

Part - 5: Applying style to ListBox, Continued

Part - 6: ListBox custom ControlTemplate

 

Part - 4: Applying basic style to ListBox

In last 3 posts, we have learnt basic usage of ListBox control, examined some important properties of ListBox control and populating ListBox control with data (static and DataBinding). Every time we have run the application, simple ListBox control displayed items without any formatting. In this article we will look at applying some styles to ListBox control.

Controls in WPF has a default ControlTemplate applied to it which resides in Themes folder. Template is a tree of visual elements that define the look and feel of control. Hence a control consists of multiple visual elements. Every control exposes some properties that can be modified to apply basic formatting to control. Instead of modifying these properties directly on individual controls, WPF introduced a better option called Style which provides a convenient way to group control properties, modify their values and then apply style to more than one element. If you are new to concepts of Style, I would recommend you to have a look at Style Post first. To customize the look and feel of control entirely, we can create custom ControlTemplate and apply to existing control.

This post covers modifying existing properties of ListBox control and next post covers creating custom ControlTemplate for ListBox control.

Below image shows template of ListBox control with different layers in it. ListBox derives from ItemsControl so you can see one to one mapping of layers between ListBox control and ItemsControl. We can either use ItemsControl directly or we can use derived controls like ListBox, Treeview, Listview to get advantage of functionalities already implemented in these controls.

ListBox Structure (Layers)

ListBox layout structure

First let’s understand briefly what each layer means and then we would customize each layer.

1. ItemsControl is framework control that can contain list of items. ListBox control derives from ItemsControl with added functionality related to ListBox. Here, we can set properties that apply directly to ListBox. When we create a new ControlTemplate, it is applied to this layer. Other layers still remain same. Template property is used to apply new ControlTemplate.

2. ItemsPanel is the layout control for organizing all items inside the control. ListBox control has VirtualizingStackPanel as its default layout control which arranges all items in vertically. We can use other layout panels like StackPanel, WrapPanel, DockPanel instead of default VirtualizingStackPanel. If we use StackPanel, items will be displayed Horizontally or Vertically. VirtualizingStackPanel is advanced StackPanel with better performance. If we use WrapPanel items will wrap Horizontally or Vertically when there is no space available. ItemsPanel property is used to apply new Panel.

3. ItemContainer is the container/wrapper for  each individual data item. ListBoxItem is the default ItemContainer for ListBox control. When we DataBind ListBox to data source (.net objects) then ListBoxItem is created by default for each item. ItemContainerStyle property is used to apply new Style.

4. Actual data item: This is a simple TextBlock control that holds data item. This is the layer where we apply DataTemplate to determine what and how data is displayed for each item in ListBox. ItemTemplate property is used to apply new DataTemplate.

To get this more interesting, below is the sample of what our ListBox control would look like when we apply properties to different layers of ListBox control.

ListBox style

ListBox style with WrapPanel

If that sounds interesting to you, follow the next post which explains how to achieve this along with code. It took a lot time for me to create above images (layer mapping) and style so if you feel this post is worth reading, please provide your comments and refer to others too.

Sunday, 3 March 2013

Part 3: Binding ListBox to XML

This post is the third in the series of ListBox control. Here is the reference of all the post in this series for quick reference.

Part - 1: ListBox basics - Adding Items manually to ListBox and understanding properties of ListBox

Part - 2: Data Binding in ListBox (Binding ListBox to data source)

Part - 3: Binding ListBox to XML

Part - 4: Applying style to ListBox

Part - 5: Applying style to ListBox, Continued

Part - 6: ListBox custom ControlTemplate

 

Part 3: Binding ListBox to XML

WPF provides very handy control “XmlDataProvider” that can be used to load XML from variety of sources (i.e provides xml data in XAML, separate XML file or set the XMLDocument programmatically).

In XAML below, we added XmlDataProvider to windows resources and provided xml data in XAML.

<XmlDataProvider x:Key="FruitsXML">
<x:XData>
<Fruits>
<Fruit Name="Apple">
<ImagePath>Images\\Apple.png</ImagePath>
<Calories>61</Calories>
<Vitamins>A,C</Vitamins>
</Fruit>
<Fruit Name="Orange">
<ImagePath>Images\\Orange.png</ImagePath>
<Calories>51</Calories>
<Vitamins>A,B1,C</Vitamins>
</Fruit>
</Fruits>
</x:XData>
</XmlDataProvider>


Binding ListBox to XmlDataProvider

<ListBox Name="lstFruits" ItemsSource="{Binding Source={StaticResource ResourceKey=FruitsXML}, XPath=Fruits/Fruit}" DisplayMemberPath="@Name" SelectedValuePath="ImagePath"></ListBox>


There are 4 important parts in binding:



Binding Source is FruitsXML which is a XmlDataProvider static resource defined in windows resources section.


XPath: Source is set to entire xml data. Hence we set XPath to “Fruits/Fruit” which binds ListBox to all Fruit elements.


DisplayMemberPath: Each item in ListBox is bound an instance of Fruit element from XML, so we need to choose which child element/attribute of Fruit element to display. We choose to display Name attribute. “@” symbol is used to indicate attribute.


SelectedValuePath: SelectedValuePath is set to “ImagePath” element of Fruit. Hence when we access “SelectedValue” property in code, it will return ImagePath of selected item.


Using XML File instead of static XML data


XmlDataProvider has Source property which can be used to specify path of XML file to load data. We can move XML data provided in XAML to separate XML file and then specify Source property of XmlDataProvider XML file. Remaining code would be same for binding ListBox.

Part - 2: Data Binding in ListBox

This post is the second in the series of ListBox control. In previous post, we learned some basic of ListBox control, adding items manually to ListBox control in XAML and code behind, and examining some properties of ListBox control.

Here is the reference of all the post in this series for quick reference.

Part - 1: ListBox basics - Adding Items manually to ListBox and understanding properties of ListBox

Part - 2: Data Binding in ListBox (Binding ListBox to data source)

Part - 3: Binding ListBox to XML

Part - 4: Applying style to ListBox

Part - 5: Applying style to ListBox, Continued

Part - 6: ListBox custom ControlTemplate

 

Part - 2: Data Binding in ListBox

In last post we learnt how to add static items to ListBox in XAML and code. But Most of the times we need to populate ListBox control by binding the control to some data source, instead of adding items manually. Data source can be xml, business object, DataTable and some other type that contains data.

Binding ListBox to Custom Business Object

Let’s create a simple class “Fruit” to hold fruit information.

public class Fruit
{
public string Name { get; set; }
public string ImagePath { get; set; }
public Int32 Calories { get; set; }
public string Vitamins { get; set; }
}


Add simple ListBox control to XAML

<ListBox Name="lstFruits"></ListBox>


In code behind (constructor), Create a list of Fruits and bind to ListBox control.

List<Fruit> myFruits = new List<Fruit>()
{
new Fruit() { Name = "Apple", ImagePath = "Images\\Apple.png", Calories = 61, Vitamins = "A,C" },
new Fruit() { Name = "Orange", ImagePath = "Images\\Orange.png", Calories = 51, Vitamins = "A,B1,C" },
new Fruit() { Name = "Grape", ImagePath = "Images\\Grapes.png", Calories = 40, Vitamins = "C" },
new Fruit() { Name = "Mango", ImagePath = "Images\\Mango.png", Calories = 80, Vitamins = "A,B1,C" }
};

lstFruits.ItemsSource = myFruits;


ItemSource property can be bound to any data source that implements IEnumerable. Generic List is one of them that implements IEnumerable.


Output:



In above image, it is visible that ListBox control is correctly bound to the data source as it shows 4 items in the list. Each item in ListBox is bound to an instance of Fruit class. As we have not specified any property of Fruit class, by default ToString() method of Fruit object is called which returns “ListboxSample.Fruit” value. i.e <Namespace.ClassName>


Modify XAML to bind to Name property by adding DisplayMemberPath

<ListBox Name="lstFruits" DisplayMemberPath="Name"></ListBox>

and here is the output



Now we examine the properties as we did in post 1.



One noticeable difference is that “SelectedItem” and “SelectedValue” property returns type “ListBoxSample.Fruit” instead of “ListBox.ListBoxItem” as each item is bound to instance of Fruit class. So to access properties we type cast to Fruit class.


Now let’s add one more property “SelectedValuePath”.

<ListBox Name="lstFruits" DisplayMemberPath="Name" SelectedValuePath="ImagePath"></ListBox>

Examine the difference.



lstFruits.SelectedValue now directly returns value of “ImagePath” property from Fruit class instead of an instance of Fruit class. Many times its quite useful to bind “SelectedValuePath” property to Unique Identifier (ID) of class so we can directly get Unique Identifier of selected item.


Some more fun with ListBox DataBinding.


Add Image control below ListBox control. Bind Image control Source property to SelectedValue property of ListBox control. This is called Element to Element binding.

<Image Grid.Row="1" Source="{Binding ElementName=lstFruits, Path=SelectedValue}" Stretch="Uniform"></Image>


Run the application and select items in ListBox.



As we have specified SelectedValuePath property of ListBox to ImagePath property of Fruit class, when any item is selected in ListBox control, SelectedValue property  of ListBox will return ImagePath of selected fruit item. Now we have bound Source property of Image control to SelectedValue property of ListBox control which would return ImagePath. Hence selecting fruit in ListBox will show image below.


ListBox also provides an alternative way of achieving same result.


IsSynchronizedWithCurrentItem


When ListBox control is bound to Data Source, internally an instance of ICollectionView is created depending on the type of of Data Source and then this view is bound to ListBox. If IsSynchronizedWithCurrentItem of ListBox is set to True, when user select any item in ListBox control, same item is set as current item in underlying view. This way if any other control (in our case Image control) is bound to any property of same data source, then it would reflect value from currently selected item in ListBox.


Let’s see what it means?


First of all we need to bind both ListBox control and Image control to same data source. Here DataContext property becomes more useful. DataContext property is present in every control and can be set to any data source. When DataContext is set in parent control, all child controls can inherit that data source from parent control. Hence we set DataContext property of entire Window.

List<Fruit> myFruits = new List<Fruit>()
{
new Fruit() { Name = "Apple", ImagePath = "Images\\Apple.png", Calories = 61, Vitamins = "A,C" },
new Fruit() { Name = "Orange", ImagePath = "Images\\Orange.png", Calories = 51, Vitamins = "A,B1,C" },
new Fruit() { Name = "Grape", ImagePath = "Images\\Grapes.png", Calories = 40, Vitamins = "C" },
new Fruit() { Name = "Mango", ImagePath = "Images\\Mango.png", Calories = 80, Vitamins = "A,B1,C" }
};

this.DataContext = myFruits;


DataContext of entire window is set to list of fruits. Hence ListBox control and Image control in Window would inherit data source from Window.

<ListBox Name="lstFruits" ItemsSource="{Binding}" DisplayMemberPath="Name" SelectedValuePath="ImagePath" IsSynchronizedWithCurrentItem="True"></ListBox>

<Image Grid.Row="1" Stretch="Uniform" Source="{Binding ImagePath}"></Image>


As ListBox inherits data source from parent, ItemSource for ListBox is set to empty Binding. IsSynchronizedWithCurrentItem = True will make sure that any item selected in ListBox will be the current item in ICollectionView.


Image control is bound to ImagePath property of Fruit class. hmm, that sounds interesting. how come any ContentControl like Image control can be bound to collection. That’s beauty of WPF DataBinding. When any property of ContentControl is bound to a property in list, current item (by default first item) in the list will be used for binding.


Now run the application and see the action.




When application is run, by default first item is the current item in ICollectionView. Hence “Apple” is selected in ListBox and Apple is displayed in Image control.


Now as we change the selection in ListBox, current item in ICollectionView is updated and hence image gets displayed for selected item.



This is very handy feature and useful in different scenarios.


I hope this would provide you a good insight into DataBinding.

Part - 1: ListBox basics

In this series of ListBox control, we would cover basics to advanced usage of ListBox control.

Part - 1: ListBox basics - Adding Items manually to ListBox and understanding properties of ListBox

Part - 2: Data Binding in ListBox (Binding ListBox to data source)

Part - 3: Binding ListBox to XML

Part - 4: Applying style to ListBox

Part - 5: Applying style to ListBox, Continued

Part - 6: ListBox custom ControlTemplate

 

Part - 1: ListBox Basics

ListBox control in WPF falls in category of Items Controls and used to to display list of related items. Below is the basic syntax of ListBox control.

<ListBox Name="lstFruits">
<ListBoxItem Content="Apple"></ListBoxItem>
<ListBoxItem Content="Oranges"></ListBoxItem>
<ListBoxItem Content="Mango"></ListBoxItem>
<ListBoxItem Content="Grapes"></ListBoxItem>
<ListBoxItem Content="Banana"></ListBoxItem>
</ListBox>


In above code, ListBox is a control and contains list of ListBoxItem. ListBoxItem is a specialized type of ContentControl for ListBox control. Run the application to see your ListBox in action.


Output:



To examine the properties of ListBox control, I have added Button control, handled click event of control, put the breakpoint in button click event in code, added multiple properties to watch in watch window, run the application, select “Oranges” item, breakpoint is hit and here is what I see in my properties watch window.



Tip: QuickWatch window can be used to quickly examine  value of any property at runtime. Watch window can be to add multiple properties to watch and examine their properties when they are available.


Watch window has 3 columns. Name is name of the property to watch. Value is the current value in that property. Type is the type of the value that property returns.



1. lstFruits.Items.Count = 5 = number of items in ListBox control.


2. lstFruits.SelectedIndex = 1 = As we have selected Oranges. Note: Index starts by 0.


3. lstFruits.SelectedItem: This is interesting. We would expect “Oranges” string. But if we look at the Type returned by this property, it is object and not string. As we have added ListBoxItem in ListBox, it is returning object of type ListBoxItem corresponding to “Oranges”. We can get “Oranges” text by using Content property as ListBoxItem is a ContentControl and every ContentControl has Content property. Check 4th point for the syntax.


4. ((ListBoxItem)lstFruits.SelectedItem).Content: lstFruits.SelectedItem will return object. Hence we need to type cast to “ListBoxItem” and then we can access “Content” property which would be our “Oranges” string.


5. lstFruits.SelectedValue: This is same as SelectedItem property. In this case, both are some value but we can provide different values for both, which we would cover when we DataBind to custom objects.


6. lstFruits.SelectedItems: returns collection of items that are selected in ListBox. Type column shows type returned by this property which is “SelectedItemCollection”.  Value shows says “Count = 1”, because Count is the default property when no property is specified. We can enumerate this collection to get individual selected items.


Syntax for enumeration:

foreach (ListBoxItem item in lstFruits.SelectedItems)
{

}

By default, “SelectionMode” property of ListBox control is set to “Single”. Below are the possible values for “SelectionMode” property.


SelectionMode:


Single (Default): Single means only one value can be selected.
Multiple: Multiple means multiple values can be selected.
Extended. Extended allows selection of multiple values in combination with CTRL or SHIFT key. Use CTRL key to select/de-select individual random items and SHIFT key to select consecutive items.


SelectedItems property is more meaningful when SelectionMode is set to Multiple or Extended. In this case we can select multiple items in ListBox control and access those selected items using SelectedItems property.


7. lstFruits.Items: returns collection of all items in ListBox control. This is useful when we want to enumerate all items or we want to perform other possible operations on collection.


I hope this would provide a good insight into some useful properties of ListBox control.


In ListBox control above we added ListBoxItem, but ListBox is not just restricted to ListBoxItem, it can contain any ContentControl as items. See below image for different types of ContentControl added.



Note: I have made 2 changes:



Replaced ListBoxItem with CheckBox



Added HorizontalContentAlignment = “Stretch”. So that all CheckBox controls occupies entire horizontal space in ListBox control.


Now run the application.



We select 3 items “Oranges”, “Grapes” and “Banana”. So SelectionMode property of ListBox control (“Single”) does not affect because we are not selecting items but we are using CheckBox to check/select them. As we are not selecting the items, hence all properties we examined above for selection would not be useful. Let examine the Watch.



Interesting, so how do I get the checked items. Simple loop through the items, type case each item to CheckBox and use Checked property.

private void Button_Click(object sender, RoutedEventArgs e)
{
List<string> selectedItems = new List<string>();
foreach (CheckBox chkCurrentItem in lstFruits.Items)
{
if (chkCurrentItem.IsChecked.Value)
{
selectedItems.Add(chkCurrentItem.Content.ToString());
}
}
}


It is also possible to add combination of items in ListBox control. See below image. Any control derived from ContentControl can be added as individual item to ListBox.



Dynamically adding items to ListBox in Code

lstFruits.Items.Add("Apple");
lstFruits.Items.Add("Oranges");
lstFruits.Items.Add("Mango");
lstFruits.Items.Add("Grapes");
lstFruits.Items.Add("Banana");


Above code will add 5 items to ListBox and each item would be implicitly converted to ListBoxItem.

lstFruits.Items.Add(new CheckBox() { Content = "Apple" });
lstFruits.Items.Add(new CheckBox() { Content = "Oranges" });
lstFruits.Items.Add(new CheckBox() { Content = "Mango" });
lstFruits.Items.Add(new CheckBox() { Content = "Grapes" });
lstFruits.Items.Add(new CheckBox() { Content = "Banana" });


Here we add 5 CheckBox control to ListBox.


I hope this introduction would help you to understand basics ListBox control and some important properties. In next article we would look at Data Binding in ListBox control.