Click here to Skip to main content
Licence CPOL
First Posted 14 Oct 2008
Views 23,679
Downloads 533
Bookmarked 38 times

WPF CheckListBox/RadioListBox + CheckComboBox/RadioComboBox

By | 30 Oct 2008 | Article
Intended for LOB applications: WPF CheckListBox/RadioListBox with bound datatype.

Introduction

In LOB applications, we have to design many windows, and many entities are bound to entry fields. Also, sometimes, there are enums or bool[] arrays to be used. Therefore, I had a look at the chances I got to bind some user control to an enum data type. There is no CheckListBox as in WinForms, and WPF shows the whole power when a ListBox has to be customized to a CheckListBox. A template-style will do for that more or less. It is more difficult when the CheckListBox should be bound to a flagged enum or is a RadioListBox.

WPFCheckListBox_Sample.png

What I wanted to achieve

In the case of showing all enum items to the user, I wanted to do the following:

  • drop a control from the toolbox on the form
  • set a binding to the entity, specifying the property name

With declaring the property in the business object as an enum type, I already do everything beforehand, so I do not have to think again about the enum items and setting the ItemSource, and so on.

Using the code

Like the specs, you just drop the desired control onto the form and set the binding. In the sample, all the necessary parts are contained to show the functionality:

<clb:RadioListBox Name="listBoxType" 
                  CheckedValue="{Binding PropType, Mode=TwoWay}"/>

<clb:CheckListBox Name="listBoxFeature"
                  CheckedValue="{Binding PropFeature, Mode=TwoWay}"/>

The CheckedValue dependency property holds the bound data property from the entity. It is important to specify that the binding is TwoWay.

Sometimes, you don't have an enum data type but a bool[] array or anything else. In this case, there is no way to find out what the items to appear in the selection list are. So, you must somehow declare and propagate the collection to the control. You can do this in the code or in XAML. In any case, this has to be done before the first binding occurs. Here is a sample in XAML:

<Window.Resources>
    <coll:ArrayList x:Key="actionList">
        <clb:CheckItem KeyValue="0" Display="action 0"/>
        <clb:CheckItem KeyValue="1" Display="action 1"/>
        <clb:CheckItem KeyValue="2" Display="action 2"/>
    </coll:ArrayList>

    <coll:ArrayList x:Key="arrayList">
        <clb:CheckItem KeyValue="0" Display="item 0"/>
        <clb:CheckItem KeyValue="1" Display="item 1"/>
        <clb:CheckItem KeyValue="2" Display="item 2"/>
        <clb:CheckItem KeyValue="3" Display="item 3"/>
    </coll:ArrayList>
</Window.Resources>

<clb:RadioListBox Name="listBoxAction" 
                  CheckListArray="{StaticResource actionList}" 
                  CheckedValue="{Binding PropAction, Mode=TwoWay}" />

<clb:CheckListBox Name="listBoxArray"
                  CheckListArray="{StaticResource arrayList}" 
                  CheckedValue="{Binding PropArray, Mode=TwoWay}"/>

The CheckListArray holds the collection to be shown in the list. Specify the KeyValue if you want the chosen value as, e.g., an integer.

What is happening when running

In the underlying base class of the CheckListBox and RadioListBox, the DataContextChanged is used to intercept on a binding to the bound property. In this case, the CheckedValue.OnDataContextChanged, the type of the bound property, is evaluated, and either a prepared collection, or the items of the enum are bound to the ItemSource of the ListBox. To keep track of the changes, a ViewModel (I call it this way, might not meet the name) is created to control the ListBox and the bound property.

This class is important, the enum could be of various types: byte, int, uint, long, ulong... They all work neat because the ViewModel uses a UInt64 array of values to keep track of the enumeration values. The corresponding data types are boxed/unboxed accordingly.

The [Flags] attribute is very important on an enum data type. Without this, only one choice can be checked, and even a CheckListBox is used.

If someone wants to do all this before the first binding, the method CreateViewModel could be called manually by specifying the corresponding type.

public void CreateViewModel(Type boundType)
{
   if (boundType==null)
   {
      return;
   }
   if (this.CheckViewModel == null || this.CheckViewModel.BoundType != boundType)
   {
      Type _viewBase = typeof(CheckViewModel<>);
      Type _viewType = _viewBase.MakeGenericType(boundType);

      this.CheckViewModel = (ICheckViewModel)Activator.CreateInstance(_viewType);
      this.CheckViewModel.HostParent = this;
      this.CheckViewModel.IsRadioMode = this.isRadioMode;  // is passed by constructor

      if (this.CheckListArray != null)
      {
          List<CheckItem> _itemList = new List<CheckItem>();
          foreach (CheckItem _checkItem in this.CheckListArray)
          {
             _itemList.Add(_checkItem);
          }
          this.CheckViewModel.CheckItems = _itemList;
      }
      else
      {
          this.CheckViewModel.InitDiscovery();
      }
   }
   if (this.CheckViewModel != null && this.ItemsSource == null)
   {
      this.ItemsSource = this.CheckViewModel.CheckItems;
      this.DisplayMemberPath = "Display";
      this.SelectedValuePath = "KeyValue";
      this.SelectionMode = SelectionMode.Single;
   }
}

Overview

The CheckModelView is encapsulated in the CheckListBoxBase. From this base class, the CheckListBox and the RadioListBox are derived. The main reason for this is the different template they use for the ListBox:

CheckViewModel.png

So maybe, it helps someone, or some real WPF-experts (you name them) might come up with a better solution. Cheers!

History

  • 15.10.2008 > Initial publication.
  • 31.10.2008 > Update: CheckComboBox and RadioComboBox.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

christoph braendle

CEO
dialogik software
Switzerland Switzerland

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionHow to customize clb:CheckItem? PinmemberMasupilamix5:02 3 Dec '11  
AnswerRe: How to customize clb:CheckItem? Pinmemberchristoph braendle2:55 6 Dec '11  
QuestionHow to bind date to CheckListArray?Not using StaticResource. Pinmemberartan00817:35 10 May '10  
AnswerRe: How to bind date to CheckListArray?Not using StaticResource. PinmemberMember 32246500:14 1 Jun '10  
GeneralGet the following error Pinmembereve12320:45 6 Feb '10  
GeneralRe: Get the following error Pinmemberchristoph braendle23:23 8 Feb '10  
GeneralLike it PinmvpSacha Barber21:56 25 Oct '08  
GeneralRe: Like it Pinmemberchristoph braendle11:28 31 Oct '08  
GeneralRe: Like it PinmvpSacha Barber22:18 31 Oct '08  
GeneralRe: Like it Pinmemberchristoph braendle3:53 1 Nov '08  
GeneralRe: Like it PinmvpSacha Barber4:13 1 Nov '08  
GeneralTimely Work PinmemberKavan Shaban1:12 25 Oct '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120517.1 | Last Updated 31 Oct 2008
Article Copyright 2008 by christoph braendle
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid