Cascading Combobox in WPF

Introduction

This article explains how to create a Cascading Combobox in WPF. We know a Cascading Combobox is not available in WPF but we can create it by inheriting the feature of an existing combobox that is available in WPF. This combobox is supported in the .Net Framework ersions 4.0 and 4.5. Developing a costum combobox (Cascading Combobox) is not difficult, just do some small tasks by inheriting the combobox of the "System.Winsows. Controls.Combobox" class.

Create a new ClassLibrary project in Visual Studio from 10 ro 12 and rename the class to CascadingCombobox . Inherit the Combobox class from the "System.Windows.Controls" namespace and ensure that you have references for the following DLLs:

  • PresentationCore
  • PresentationFramework
  • Windows Core

And impliment the following namespaces related to ComboBox listed below in your class:

  • System.ComponentModel
  • System.Windows.Data
  • System.Windows.Input
  • System.Windows.Controls

The class CascadinCombobox encapuslates the two fields (IsEditable and IsTextSearchEnabled) of the base class Combobox and sets the IsEditable to true and IsTextSearchEnabled to false, so that the text search enabled property will alwas be false and IsEditable is always true.

Declare a new private property named DataList type of "IcollectionView" to help to fileter the Combobox. For more detailse about "IcollectionView" go to the following link http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview.aspx. Again create a private object of the Stack class to store the key strock text when key strock occurs on this control and removes it when delete or backspace is clicked. The datatype is string.

In the constructor of CascadinCombobox set the IsEditable property and IsTextSearchEnabled to true and false and initialize the stack class object.

public MyCascadingComboBox()

{

   this.IsEditable = true;

   this.IsTextSearchEnabled = false;

   Inputes = new Stack<string>();

}

Ovveride the "OnItemsSourceChanged" event of the base class into your class to reset the ItemsSource of the combobox to CollectionView.
 

protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)

{

    this.DataList = CollectionViewSource.GetDefaultView(newValue);

    base.OnItemsSourceChanged(oldValue, this.DataList);

}

In the preceding event I have used a CollectionViewSource collection class that belongs to the System.Windows.Dataname space. CollectionViewSource is a proxy for a CollectionView class, or a class derived from CollectionView. CollectionViewSource enables XAML code to set the commonly used CollectionView properties, passing these settings to the underlying view. CollectionViewSource has a View property that holds the actual view and a Source property that holds the source collection.

Again ovveride the OnPreviewKeyDown to capture and filter the inputs by key.
 

protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)

{

if (e.Key == Key.Back || e.Key == Key.Delete)

{

if (!string.IsNullOrEmpty(this.SearchValue))

{

if (Inputes.Count > 0)

this.SearchValue = this.SearchValue.Replace(Inputes.Pop(),string.Empty);

}

}

else

{

Inputes.Push(e.Key.ToString());

this.SearchValue = this.SearchValue + e.Key.ToString();

}

base.OnPreviewKeyDown(e);

this.DataList.Filter = this.CustomeFilter;

if (this.SearchValue.Length > 0)

this.IsDropDownOpen = true;

else

this.IsDropDownOpen = false;

}

In the preceding event I removed letters from the combobox text and call the pop(0 function of the stack when the user presses the backspace or delete key. When the user presses keys other than delete and backspace then call the stack's push function to store the text of the pressed key, also insert and remove the letter of the search value like stack. Then the Filter function is called after doing an insert or remove if the length of the searchvalue becomes not zero and when it becomes zero the dropdown panes of combobox is hidden.

This Customer Filter function Cascading Combobox class actually filters the combobox item. Then I have done some steps to filter the items.
 

private bool CustomeFilter(object item)

{

  Type TP = item.GetType();

  PropertyInfo PI = TP.GetProperty(this.DisplayMemberPath);

  string values = PI.GetValue(item).ToString();

  values = values.ToUpper();

  return values.StartsWith(this.SearchValue.ToUpper());

}


All Code

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ComponentModel;

using System.Windows.Data;

using System.Reflection;

using System.Windows.Input;

 

namespace CascadingComboBox

{

    public class ComboBox : System.Windows.Controls.ComboBox

    {

        private ICollectionView DataList { get; set; }

        private string SearchValue;

        private Stack<string> Inputes;

        public ComboBox()

        {

            this.IsEditable = true;

            this.IsTextSearchEnabled = false;

            Inputes = new Stack<string>();

        }

        protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)

        {

            this.DataList = CollectionViewSource.GetDefaultView(newValue);

            base.OnItemsSourceChanged(oldValue, this.DataList);

        }

        protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)

        {

            if (e.Key == Key.Back || e.Key == Key.Delete)

            {

                if (!string.IsNullOrEmpty(this.SearchValue))

                {

                    if (Inputes.Count > 0)

                        this.SearchValue = this.SearchValue.Replace(Inputes.Pop(), string.Empty);

                }

            }

            else

            {

                Inputes.Push(e.Key.ToString());

                this.SearchValue = this.SearchValue + e.Key.ToString();

            }

            base.OnPreviewKeyDown(e);

            this.DataList.Filter = this.CustomeFilter;

            if (this.SearchValue.Length > 0)

                this.IsDropDownOpen = true;

            else

                this.IsDropDownOpen = false;

        }

        private bool CustomeFilter(object item)

        {

            Type TP = item.GetType();

            PropertyInfo PI = TP.GetProperty(this.DisplayMemberPath);

            string values = PI.GetValue(item).ToString();

            values = values.ToUpper();

            return values.StartsWith(this.SearchValue.ToUpper());

        }

    }

}

Summery

In this illustration we came to understand how to build / create a Cascading Combobox in WPF.