LIDOR SYSTEMS

Advanced User Interface Controls and Components

Custom Drop-Down Filter for Columns in TreeListView .NET

January 19, 2010

The IntegralUI TreeListView control comes with built-in support for filtering by multiple values using AND, OR criteria and exact or prefix match. Two methods are available:

  • SetFilter - used to set filter values, matching criteria and whether exact or prefix match is used

    SetFilter(string[] values, FilterMatchCriteria criteria, FilterMode mode, bool isPrefixSearch)


  • ResetFilter - used to set remove the filter values and set the filter to its default state.

    ResetFilter()

An array of different values can be applied to the filter. By using different matching criteria: byKey, byTag, byText or byValue, the values are compared with corresponding property values of nodes or subitems. Further more, values are compared using AND or OR operator. By using OR operator, data that is filtered can match more then one value. Finally, during comaprison the values that are used for filtering can be compared using exact or prefix match.

For example: let say we have three different filter values, criteria is set to FilterMatchCriteria.byKey, mode is set to FilterMode.Or and we are using prefix search. Then the data that is shown in TreeListView control will be the nodes or subitems which have their Key property value equal to some of the filter values. During search only the first characters are compared, because we are using prefix search.

In the next section is presented how to create custom drop-down filter for DateTime values.

Let's presume that TreeListView control is placed on the Form with a Button control. The TreeListView control has two columns and some nodes. The first column contains simple text, whether the second column has DateTime values. We will apply filter only for the second column.

TreeListView control with two columns

To create a drop-down filter, a custom UserControl is used which displays MotnhCalendar control for selecting a month for specified year which will be used to filter the data in TreeListView control. The MonthCalendar control is set to show only months for selection. Here is the code used to create this UserControl:

public partial class FilterDatePanel : UserControl

{

public event EventHandler Close;

private string[] filterDates = null;

public string[] GetValues()

{

return filterDates;

}

 

public FilterDatePanel()

{

InitializeComponent();

}

 

protected virtual void OnClose(object sender, EventArgs e)

{

if (Close != null)

Close(this, e);

}

 

private void btnOk_Click(object sender, EventArgs e)

{

filterDates = new string[] { this.monthCalendar1.SelectedDate.ToString("MMM yyyy") };

OnClose(this, EventArgs.Empty);

}

 

private void btnCancel_Click(object sender, EventArgs e)

{

filterDates = null;

OnClose(this, EventArgs.Empty);

}

 

private void FilterDatePanel_Load(object sender, EventArgs e)

{

this.monthCalendar1.AllowDisplayModeChange = false;

}

}

Public Class FilterDatePanel

Public Event Close As EventHandler

Private filterDates As String() = Nothing

 

Public Function GetValues() As String()

Return filterDates

End Function

 

Public Sub New()

InitializeComponent()

End Sub

 

Protected Overridable Sub OnClose(ByVal sender As Object, ByVal e As EventArgs)

RaiseEvent Close(Me, e)

End Sub

 

Private Sub btnOk_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnOk.Click

filterDates = New String() {Me.monthCalendar1.SelectedDate.ToString("MMM yyyy")}

OnClose(Me, EventArgs.Empty)

End Sub

 

Private Sub btnCancel_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnCancel.Click

filterDates = Nothing

OnClose(Me, EventArgs.Empty)

End Sub

 

Private Sub FilterDatePanel_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load

Me.monthCalendar1.AllowDisplayModeChange = False

End Sub

End Class

At first to show the filter panel, a drop-down arrow is added to the right of header of the second column:

column.HeaderContent = "<div><table width=\"100%\"><tr><td>Header " + j.ToString() + "</td><td width=\"80%\" style=\"align:middleright\"><img index=\"0\" width=\"9\" height=\"9\"></img></td></tr></table></div>";

column.HeaderContent = "<div><table width=""100%""><tr><td>Header " & j.ToString() & "</td><td width=""80%"" style=""align:middleright""><img index=""0"" width=""9"" height=""9""></img></td></tr></table></div>"

Whenever, the drop-down arrow is clicked a filter panel will be shown, where a date can be selected. Then this value can be used for filtering the data in TreeListView. Here is the code which presents how the click from drop-down arrow is handled:

TreeListView control with DateTime filter

private void treeListView1_ContentObjectClicked(object sender, LidorSystems.IntegralUI.ObjectClickEventArgs e)

{

if (e.Object is Image)

{

TreeListViewColumn column = this.treeListView1.GetColumnAt(e.Position.X, e.Position.Y);

if (column != null)

{

Point mousePos = this.treeListView1.PointToScreen(e.Position);

 

switch (column.Index)

{

case 1:

_popupFilterDate.Show(mousePos);

break;

}

}

}

}

Private Sub treeListView1_ContentObjectClicked(ByVal sender As Object, ByVal e As LidorSystems.IntegralUI.ObjectClickEventArgs) Handles treeListView1.ContentObjectClicked

If TypeOf e.[Object] Is Image Then

Dim column As TreeListViewColumn = Me.treeListView1.GetColumnAt(e.Position.X, e.Position.Y)

If column IsNot Nothing Then

Dim mousePos As Point = Me.treeListView1.PointToScreen(e.Position)

 

Select Case column.Index

Case 1

_popupFilterDate.Show(mousePos)

Exit Select

End Select

End If

End If

End Sub

Whenever a month is selected and OK button is presed, the selected date is added to the variable which holds the filter values. Also a Close event is created to notify the TreeListView control that filter panel is closed. By handling this event, the filter can be applied to the TreeListView by using the value retrieved from FilterDatePanel.

TreeListView control with applied DateTime filter

private void filterDatePanel_Close(object sender, EventArgs e)

{

if (_popupFilterDate != null)

_popupFilterDate.Close(ToolStripDropDownCloseReason.ItemClicked);

}

 

private void OnFilterDatePanelClosing(object sender, ToolStripDropDownClosingEventArgs e)

{

TreeListViewColumn column = this.treeListView1.GetColumnAt(currentMousePos.X, currentMousePos.Y);

if (column != null)

column.SetFilter(_filterDatePanel.GetValues(), FilterMatchCriteria.byKey, FilterMode.Or, true);

else

{

foreach (TreeListViewColumn currentColumn in this.treeListView1.Columns)

currentColumn.ResetFilter();

}

 

this.treeListView1.UpdateLayout();

currentMousePos = Point.Empty;

}

 

private void OnFilterDatePanelOpening(object sender, CancelEventArgs e)

{

currentMousePos = this.treeListView1.PointToClient(Control.MousePosition);

}

Private Sub filterDatePanel_Close(ByVal sender As Object, ByVal e As EventArgs)

If _popupFilterDate IsNot Nothing Then

_popupFilterDate.Close(ToolStripDropDownCloseReason.ItemClicked)

End If

End Sub

 

Private Sub OnFilterDatePanelClosing(ByVal sender As Object, ByVal e As ToolStripDropDownClosingEventArgs)

Dim column As TreeListViewColumn = Me.treeListView1.GetColumnAt(currentMousePos.X, currentMousePos.Y)

If column IsNot Nothing Then

column.SetFilter(_filterDatePanel.GetValues(), FilterMatchCriteria.byKey, FilterMode.[Or], True)

Else

For Each currentColumn As TreeListViewColumn In Me.treeListView1.Columns

currentColumn.ResetFilter()

Next

End If

 

Me.treeListView1.UpdateLayout()

currentMousePos = Point.Empty

End Sub

 

Private Sub OnFilterDatePanelOpening(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs)

currentMousePos = Me.treeListView1.PointToClient(Control.MousePosition)

End Sub

The complete sample project can be downloaded from Download links section.

Newsletter


Sign-up to our newsletter and you will receive news on upcoming events, latest articles, samples and special offers.
Name: Email: *
*By checking this box, I agree to receive a newsletter from Lidor Systems in accordance with the Privacy Policy. I understand that I can unsubscribe from these communications at any time by clicking on the unsubscribe link in all emails.