Click here to Skip to main content
15,867,885 members
Articles / Programming Languages / C#
Article

ListView Control with built-in support for hiding columns using a context menu, in C#

Rate me:
Please Sign up or sign in to vote.
3.08/5 (14 votes)
6 Dec 20053 min read 153K   2.8K   52   30
A ListView control with built-in support for hiding columns using a context menu.

Sample Image - ListView.jpg

Introduction

Every time I use a ListView, I think that I should provide a context menu to support the hiding of columns, which is very much required if the number of columns are more and you need to scroll to see the last column. I often think why the ListView doesn't come with this support built-in? So I decided to implement a ListView with built-in support for hiding columns, using a context menu. Using this extended listview which I named as ListViewEx, I get a context menu built-in which can hide columns. The best part is I don't have to create the menu items. Every time I add a new column, the menu for hiding it is ready by default :-).

Background

A ListView control allows you to display a list of items with an item text and, optionally, an icon to identify the type of item. When the View property of the control is set to View.Details, the items can be displayed in different columns. A ColumnHeader class represents a single column in the ListView control. A ListView contains a ColumnHeaderCollection class which stores the column headers that are displayed in the ListView control when the View property is set to View.Details. The ListView.ColumnHeaderCollection stores ColumnHeader objects that define the text to display for a column as well as how the column header is displayed in the ListView control when displaying columns. When a ListView displays columns, the items and their subitems are displayed in their own columns.

Implementation

I have implemented the ListViewEx control by extending the ListView, ColumnHeaderCollection, and ColumnHeader classes.

ColumnHeaderEx Class

This class extends the ColumnHeader class and provides the following properties and an event to notify that the visibility of the column has changed.

C#
 /// <summary>
 /// Property to change the visibility of the column
 /// </summary>
 public bool Visible {
     get{return columnVisible;}
     set{ShowColumn(value);}
 }

 /// <summary>
 /// Menu item which represents the column.
 /// This menuitem can be used to add to the
 /// context menu, which can inturn used to
 /// Hide/Show the column
 /// </summary>
 public MenuItem ColumnMenuItem {
     get{return menuItem;}
 }
/// <SUMMARY>

 /// <summary>
 /// This event is raised when the visibility of column
 /// is changed.
 /// </summary>
 public event EventHandler VisibleChanged;

When the visibility of the column is changed, the subscriber for this event (ColumnHeaderCollectionEx) is notified and the menuitem is checked/unchecked depending on weather the column is hidden or displayed. The visibility of the column can be changed by changing the Visible property or by clicking the context menu, which is handled here alone. The following code does the described activity:

C#
/// <summary>
/// Method to show/hide column
/// </summary>
/// <PARAM name="visible">visibility</PARAM>
private void ShowColumn(bool visible) {
    if(columnVisible != visible) {
        columnVisible = visible;
        menuItem.Checked = visible;
        if(VisibleChanged != null) {
            VisibleChanged(this, EventArgs.Empty);
        }
    }
}

/// <summary>
/// Handler to handel toggel of menu item.
/// </summary>
/// <PARAM name="sender"></PARAM>
/// <PARAM name="e"></PARAM>
private void MenuItemClick(Object sender, System.EventArgs e) {
    MenuItem menuItem = (MenuItem)sender;
    // Ensure Column is hidden/shown accordingly
    ShowColumn(!menuItem.Checked);
}

ColumnHeaderCollectionEx Class

This class extends the ColumnHeaderCollection and contains a list of ColumnHeadersExs. Columns can be added to the collection using the Add or AddRange methods which are listed as below. Whenever a column is added to the collection, we subscribe to the VisibleChanged changed event of the column headers and keep a reference to the column in a list for further use.

C#
/// <summary>
/// Method adds a single column header to the collection.
/// </summary>
/// <PARAM name="str">Text to display</PARAM>
/// <PARAM name="width">Width of column</PARAM>
/// <PARAM name="textAlign">Alignment</PARAM>
/// <returns>new ColumnHeaderEx added</returns>
public override ColumnHeader Add(string str,
       int width, HorizontalAlignment textAlign) {
    ColumnHeaderEx column = new ColumnHeaderEx(str,
                                 width, textAlign);
    this.Add (column);
    return column;
}

/// <summary>
/// Method adds a single column header to the collection.
/// </summary>
/// <PARAM name="column"></PARAM>
/// <returns>The zero-based index into the collection
/// where the item was added.</returns>
public override int Add(ColumnHeader column) {
    return this.Add (new ColumnHeaderEx(column));
}

/// <summary>
/// Adds an array of column headers to the collection.
/// </summary>
/// <PARAM name="values">An array of ColumnHeader
/// objects to add to the collection. </PARAM>
public override void AddRange(ColumnHeader[] values) {
    // Add range of column headers
    for(int index = 0; index < values.Length; index++) {
        this.Add (new ColumnHeaderEx(values[index]));
    }
}

/// <summary>
/// Adds an existing ColumnHeader to the collection.
/// </summary>
/// <PARAM name="column">The ColumnHeader to
/// add to the collection. </PARAM>
/// <returns>The zero-based index into the collection
/// where the item was added.</returns>
public int Add(ColumnHeaderEx column) {
    // Add the column to the base
    int retValue = base.Add (column);
    // Keep a refrence in columnList
    columnList.Add(column.ColumnID, column);
    // Add the its menu to main menu
    ContextMenu.MenuItems.Add(column.ColumnMenuItem);
    // Subscribe to the visiblity change event of the column
    column.VisibleChanged += new EventHandler(ColumnVisibleChanged);
    return retValue;
}

When a column is hidden, the VisibleChanged event is fired which is handled in this class. Here, we remove the column from the base but we still have it in our list. When a column is shown, we find out the index where the column has to be displayed and insert it back. This is listed below:

C#
/// <summary>
/// Handler to handel the visiblity change of columns
/// </summary>
/// <PARAM name="sender">ColumnHeaderEx</PARAM>
/// <PARAM name="e"></PARAM>
private void ColumnVisibleChanged(object sender, EventArgs e) {
    ColumnHeaderEx column = (ColumnHeaderEx)sender;

    if(column.Visible == true) {
        // Show the hidden column
        // Get the position where the hidden column has to be shown
        ColumnHeaderEx prevHeader = FindPreviousVisibleColumn(column);
        if(prevHeader == null) {
            // This is the first column, so add it at 0 location
            base.Insert(0, column);
        }
        else {
            // Got the location, place it their.
            base.Insert(prevHeader.Index + 1, column);
        }
    }
    else {
        // Hide the column.
        // Remove it from the base, dont worry we have the
        // refrence in columnList to get it back
        base.Remove(column);
    }
}

/// <summary>
/// This method is used to find the first visible column
/// which is present in front of the column specified
/// </summary>
/// <PARAM name="column">refrence columns for search</PARAM>
/// <returns>null if no visible colums are in front of
/// the column specified, else previous columns returned</returns>
private ColumnHeaderEx FindPreviousVisibleColumn(ColumnHeaderEx column) {
    // Get the position of the search column
    int index = columnList.IndexOfKey(column.ColumnID);
    if(index > 0) {
        // Start a recursive search for a visible column
        ColumnHeaderEx prevColumn =
           (ColumnHeaderEx)columnList.GetByIndex(index - 1);
        if((prevColumn != null) && (prevColumn.Visible == false)) {
            prevColumn = FindPreviousVisibleColumn(prevColumn);
        }
        return prevColumn;
    }
    // No visible columns found in font of specified column
    return null;
}

ListViewEx Class

This class extends the ListView class. Here we don't do much, we ensure that ColumnHeaderCollectionEx is used instead of ColumnHeaderCollection, that's all. This is done by overriding the Columns property.

C#
/// <summary>
/// Gets the collection of all column headers
/// that appear in the control.
/// </summary>
public new ColumnHeaderCollectionEx Columns {
    get{return columnHeadersEx;}
}

How to use the code

This ListControlEx can be used exactly the way ListControl is used with respect to adding columns, removing columns, etc. But if you want to hide a column programmatically, you could do the following:

C#
listViewEx.Columns[4].Visible = false;
listViewEx.Columns[5].Visible = false;

Or if you don't want a menu for a particular column, try this:

C#
// We will avoid removing the first column by the user.
// Dont provide the menu to remove simple...
listViewEx.Columns[0].ColumnMenuItem.Visible = false;

Conclusion

Most of the functionality have been described here. If you find mistakes, you can correct them. Or you can send me mails explaining the bugs or mistakes you found.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
I have been working in software industry for the past 5 years now. Enjoy working on complex and new technologies. Worked on Microsoft technologies Like VC++, COM, XML, SQL. Currently working on .Net, C#.

Comments and Discussions

 
Questionporting this code to vb.net Pin
strippher5-Apr-14 18:04
strippher5-Apr-14 18:04 
GeneralMy vote of 5 Pin
Asrij Siraj7-Apr-11 23:44
Asrij Siraj7-Apr-11 23:44 
GeneralMy vote of 1 Pin
Masa114-Mar-11 22:46
Masa114-Mar-11 22:46 
Full of bugs.
GeneralMy vote of 1 Pin
idursun27-Sep-09 21:08
idursun27-Sep-09 21:08 
GeneralRe: My vote of 1 Pin
Masa114-Mar-11 22:36
Masa114-Mar-11 22:36 
GeneralAnother method to hide Pin
dfsweet6-Nov-08 23:08
dfsweet6-Nov-08 23:08 
GeneralRe: Another method to hide Pin
Mailgoatz10-Feb-11 11:22
Mailgoatz10-Feb-11 11:22 
GeneralI have problem with refresh. Pin
igomel30-Aug-07 12:21
igomel30-Aug-07 12:21 
GeneralRe: I have problem with refresh. Pin
miloszornic13-Mar-09 0:54
miloszornic13-Mar-09 0:54 
GeneralDon't bother with this. Pin
MrSmoofy16-Apr-07 5:23
MrSmoofy16-Apr-07 5:23 
QuestionDesigner bug? Pin
edupas1-Mar-06 10:11
edupas1-Mar-06 10:11 
AnswerRe: Designer bug? Pin
ChRoNoN29-Jun-06 7:31
ChRoNoN29-Jun-06 7:31 
Questionvery slow Pin
rm_pkt10-Jan-06 19:17
rm_pkt10-Jan-06 19:17 
Generalremoving columns Pin
GHoffer12-Dec-05 8:38
GHoffer12-Dec-05 8:38 
GeneralRe: removing columns Pin
Madhu Raykar12-Dec-05 19:17
Madhu Raykar12-Dec-05 19:17 
GeneralRe: removing columns Pin
GHoffer13-Dec-05 12:36
GHoffer13-Dec-05 12:36 
GeneralRe: removing columns Pin
Madhu Raykar13-Dec-05 17:37
Madhu Raykar13-Dec-05 17:37 
GeneralRe: removing columns Pin
gxdata28-Dec-05 18:59
gxdata28-Dec-05 18:59 
AnswerRe: removing columns Pin
saanj4-Nov-08 18:41
saanj4-Nov-08 18:41 
GeneralBug Pin
wcrews11-Dec-05 4:08
wcrews11-Dec-05 4:08 
GeneralRe: Bug Pin
Madhu Raykar1-Jan-06 3:14
Madhu Raykar1-Jan-06 3:14 
GeneralRe: Bug Pin
rm_pkt3-Jan-06 17:56
rm_pkt3-Jan-06 17:56 
GeneralRe: Bug Pin
Scotty B6-Feb-06 8:22
Scotty B6-Feb-06 8:22 
GeneralRe: Bug Pin
Madhu Raykar6-Feb-06 16:53
Madhu Raykar6-Feb-06 16:53 
GeneralRe: Bug Pin
senkumarr28-Jun-06 18:26
senkumarr28-Jun-06 18:26 

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

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