Sunday, June 14, 2009

Create a CheckListBox in WPF

Many developers are frustrated with lack of basic WPF controls. The WPF and WPF toolkit have some important and cool controls. However, some basic and necessary controls are still missing. But it is easy to create the basic controls in WPF. The article will show you how to create a checklistbox in WPF.

Here, I will create a custom control which will inherit from Listbox. The following code snippet shows the entire source code for the CheckListBox.

namespace MyControlLibrary
{
public class CheckListBox:ListBox
{
public CheckListBox()
{

}
///
/// Item Source of the check list box
///

public new IEnumerable ItemsSource
{
get
{
return this.ItemsSource;
}
set
{
//set the template
this.ItemTemplate = GetTemplate();
base.ItemsSource = value;

}
}

///
/// Gets or sets the property of source object. The property value will be displayed as a content of the checkbox.
///

public string DisplayMember { get; set; }
///
///
///

public string ValueMember { get; set; }


///
/// returns the template for the checkbox.
///

///
private DataTemplate GetTemplate()
{
DataTemplate template = new DataTemplate();
Binding binding = new Binding(this.DisplayMember);
FrameworkElementFactory fwfactory = new FrameworkElementFactory(typeof(CheckBox));
fwfactory.SetValue(CheckBox.NameProperty, "chk");
fwfactory.SetValue(CheckBox.ContentProperty, binding);
fwfactory.SetValue(CheckBox.TagProperty, new Binding(this.ValueMember));
template.VisualTree = fwfactory;
return template;
}

///
/// returns the checked list items.
///

public IEnumerable GetCheckListItems
{
get
{
List list = new List();
for (int index = this.Items.Count-1; index >= 0; index--)
{
CheckBox chk = GetCheckBoxFromDataTemplate(index);
if (chk != null && chk.IsChecked.HasValue && chk.IsChecked.Value)
{
list.Add(this.Items[index]);
}

}
return list;
}
}

///
/// set the checked list items
///

public IEnumerable SetCheckListItems
{
set
{
PropertyInfo listItemPorperty = null;
if(this.Items.Count > 0)
{
listItemPorperty = this.Items[0].GetType().GetProperty(this.ValueMember);
}
PropertyInfo itemPropertyInfo = null;

foreach (var item in value)
{
itemPropertyInfo = item.GetType().GetProperty(this.ValueMember);
break;
}
if (itemPropertyInfo == null listItemPorperty == null) { return; }

for (int index = this.Items.Count - 1; index >= 0; index--)
{
foreach (var item in value)
{
if (listItemPorperty.GetValue(this.Items[index], null) == itemPropertyInfo.GetValue(item, null))
{
CheckBox chk = GetCheckBoxFromDataTemplate(index);
if (chk != null)
{
chk.IsChecked = true;
}
}
}

}
}
}

///
/// returns the checkbox from the data template.
///

///
///
private CheckBox GetCheckBoxFromDataTemplate(int index)
{
ListBoxItem item = this.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
if (item == null) { return null; }

DataTemplate template = item.ContentTemplate;

Border border = VisualTreeHelper.GetChild(item, 0) as Border;
ContentPresenter cp = border.Child as ContentPresenter;
return template.FindName(template.VisualTree.Name, cp) as CheckBox;
}

}
}

The following XAML shows how can you use this control :


<Window x:Class="MyControlLibrary.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:chklst="clr-namespace:MyControlLibrary"
Title="Window1" Height="300" Width="300">

<chklst:checklistbox name="chklstBox"/>

</window>



Now set the Item source of the CheckListBox:

ObservableCollection col = new ObservableCollection()
{
new {Name="Setu", ID="1"},
new {Name="Ledu", ID="2"},
new {Name="Tonmoy", ID="3"}
};
chklstBox.DisplayMember = "Name";
chklstBox.ValueMember = "ID";
chklstBox.ItemsSource = col;

You can get the checkedList items by using the GetCheckListItems property and set the checkedlist items by using the SetCheckListItems property.

This is how you can easily create a CheckListBox. Now if you want to create RadioButtonListBox, you can follow the same procedure. All you need to do is just replace the CheckBox by the RadioButton.

Hope this Helps!

No comments: