
Introduction
First of all, I must say that English is not my native language, so be indulgent with my text. The TemplateListBox
class inherits the ListBox
class, and thus behaves mainly in the same way. The TemplateListBox
extends the ListBox
control by adding collapsible items, and providing a simple way to add multiples controls (or rather a simulation of controls) into a ListBox
item. In the template item of a TemplateListBox
, you can put controls to display them at any position you want, and do it at design time as if you put them in a UserControl
.
Disclaimer: This code is provided "As Is"; I will not take responsibility for any problems caused due to its use.
Background
In Web Forms world, we have a control named Repeater
, but in the Windows Forms world, that kind of a control doesn't exist. With the TemplateListBox
, you will be able to have a Repeater
control in the Windows Forms World.
My first try was to use a Panel
control with UserControls in it, but that kind of an approach is too heavy in memory usage, and too much slow when we have many items to display; so I tried the CheckedListBox
approach, i.e., drawing controls rather than creating real ones. I also use Reflection to simulate the behaviors of real controls.
Using the code
To use the TemplateListBox
control, you must work with two classes:
TemplateListBox
TemplateItem
You can do this in four steps.
- Create a new
TemplateListBox
on your form.
- Set the
TemplateItemName
and DataSource
properties of the TemplateListBox
control in the Form_Load
event of the Form
like in the sample below. Note that the CreateDataSource
method in this sample returns a DataView
object.
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
TemplateListBox1.TemplateItemName = "UserControl1"
TemplateListBox1.DataSource = CreateDataSource()
- Create the template item. One way to do this is to add a new
UserControl
in your project (use the same name of the TemplateItemName
property value from step 2) and replace the heritage from the UserControl
class with the TemplateItem
class. After that, place the controls you want on the template item like in the Figure 1 (note that I have only tested LinkLabel
, Label
, Button
, and CheckBox
controls).
In the UserControl
, you will see a delimiter line which separates the heading from the detail section (the height of the heading can be modified with the HeadingHeight
property). Note that the heading will be the only visible part when the item of the TemplateListBox
collapses.

Figure 1
- Set the bindings for each control you want to in the
UserControl
constructor (New
) using the DataBindingItemList
collection like in the sample below. In the sample, LinkLabel1
is the control, Text
is its property to bind, and StringValue
is the data field name from the DataSource
(in my example, the DataSource
is a DataView
).
Public Sub New()
MyBase.New()
InitializeComponent()
InitializeComponent()
Me.DataBindingItemList.Add(LinkLabel1, "Text", "StringValue")
End Sub
More features
Let's see more features by analyzing the other sample code lines below.
With the TooltipCtrl
property, you can set the Tooltip
control that will be used in the TemplateListBox
, for each control that you want to set a tooltip text in the template item (I'll show you a sample in the next section).
The SetItemExpandable
method allows a TemplateListBox
item to be expandable or not. The default behavior can be set with the ItemExpandable
property.
Before the TemplateListBox
is shown, you can expand or collapse an item with the SetItemExpanded
. The default behavior can be set with the ItemExpanded
property.
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
TemplateListBox1.TemplateItemName = "UserControl1"
TemplateListBox1.DataSource = CreateDataSource()
TemplateListBox1.TootipCtrl = ToolTip1
TemplateListBox1.SetItemExpandable(0, False)
TemplateListBox1.SetItemExpanded(1, True)
TemplateListBox1.SetItemExpanded(3, True)
End Sub
If you want more custom initializations, you can use the CustomDataInitialization
event. Note that the BindingMode
property value of the TemplateListBox
must be Custom
or AutoAndCustom
for this event to be triggered. This event is triggered each time a TemplateListBox
item must be drawn.
If you have set the TemplateListBox
TooltipCtrl
property, you can set the tooltip text for each control you want, by using the SetControlTooltipText
method, and for performance, you can also use the SetControlStaticTooltipText
method if your tooltip text never changes for each TemplateListBox
item.
To set a control invisible or disabled, you must use SetControlVisible
and SetControlEnabled
, respectively.
Private Sub UserControl1_CustomDataInitialization(ByVal e As _
WindowsControlLibrary7.CustomDataInitializationEventArgs) _
Handles MyBase.CustomDataInitialization
SetControlTooltipText(e.ListItemIndex, LinkLabel1, _
"Tooltip" & e.DataItem(1).ToString)
SetControlStaticTooltipText(Button1, "This is always the same text !")
SetControlStaticTooltipText(Label1, "This is always the same text !")
If e.ListItemIndex Mod 2 = 0 Then
SetControlVisible(e.ListItemIndex, Label1, True)
Else
SetControlVisible(e.ListItemIndex, Label1, False)
End If
If e.ListItemIndex = 3 Then
SetControlEnabled(e.ListItemIndex, Button1, False)
End If
End Sub
Note that, for now, my control supports only two events: LinkClicked
event for the LinkLabel
control and all controls that inherits the LinkLabel
class, and the Click
event for all other controls (you can see a sample from the UserControl
of the two events in the code below).
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
MsgBox("Button1 of Item" & Me.TemplateListBoxParent.SelectedIndex)
End Sub
Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs)
MsgBox("LinkLabel1 of Item" & Me.TemplateListBoxParent.SelectedIndex)
End Sub
To see all the features of the TemplateListBox
, check the class diagram (figure 2).
Class diagram
The class diagram shows the classes with their public properties, methods, and events:

Figure 2
Points of Interest
At the beginning of the development of this control, to draw each control, I used a distinct method for each one. The problem with that solution is that we are limited to the controls we know. For example, that solution will not work with a custom control which has implemented its own Paint
method. So, I replaced all those functions by only one (PaintControl
), which makes it possible to copy the appearance of a control in an image object and then drawing it in the TemplateListBox
items. Thanks to reflection that makes all this possible. By the way, I also used reflection to simulate the behavior of all controls in the items of a TemplateListBox
control.
History