Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Context Menu for ListView Column Manipulation

0.00/5 (No votes)
26 Jan 2004 4  
This article implements a simple context menu for the column headers in a ListView control. After clicking on a column, the user can set the column alignment, edit its name, delete the selected column or add a new column to the ListView control. ListView's built-in column reorder option is explained

ListView Context Menu Demo

Getting Started

Bring up the demo project's Form1 in Design mode in Visual Studio. Notice that a System.Windows.Forms.ContextMenu has been dropped on to the apron just below the lower edge of Form1. Click on it. Notice that the words "Context Menu" appear at the top of Form1. Click on that. Now compare what you see there with the article's screen shot. They should look similar.

To implement your own, just start adding descriptive names in the blanks "type here" - Off to the right in the "type here" blank, if you want menu choices to extend to the right as does the demo's column alignment choices, or the "type here" blank below like the Column Delete and Column Add choices. Now all you have to do is code what you want to happen when a user clicks on one of these options and make the menu visible at appropriate times.

To implement a context menu of your own, just drop a context menu object from the form designer toolbox on to the form apron, then type in the choices you want to present. Bring up the menu in your program and respond to the events fired when the user clicks on a context menu choice.

When and How to Bring up the ListView Context Menu

Windows users are conditioned by the boys and girls of Redmond that when they want to change something they click on it. So naturally, clicking on the column header area (Col 1 Col2 ... ) should bring up the context menu.

Also, you have to know which column the user has clicked on. Fortunately, each ListView control has a column click event. It fires in response to a click in the column header area. It provides an index for the column clicked from which we can define all manner of things about the selected column. Below is my lengthy column click code. Don't let it frighten you away, it's really quite simple.

First, the column's zero based index (zero is the left column) is grabbed off the ColumnClickEventArg e and sequestered off in a field of the form1 object. We also save the current column's text alignment locally.

The long "if alignment ==" ladder is optional. All it does is place a radio button check to show the selected column's current text alignment when that sub choice is popped out to the right.

Finally, we display (show) the context menu. An improvement here would be to get the ListView's client area, then use that to determine the location of the ContextMenu. Right now, it displays at position 50,50 near your cursor.

private void listView1_ColumnClick(object sender, 
     System.Windows.Forms.ColumnClickEventArgs e)
{
    // save the zero based index of the column

    // you clicked on in a Class visible field

    clickedColumnIndex = e.Column;
    // Get the current column horizontal text alignment

    HorizontalAlignment align = 
      listView1.Columns[clickedColumnIndex].TextAlign;
    
    // on the context menu, reflect the current horizontal

    // text alignment of the column you just

    // clicked on in the Column Context menu

    if(align == HorizontalAlignment.Center)
    {
        menuItem4ColAlignCenter.Checked = true;
        menuItem4ColAlignCenter.RadioCheck = true;
        menuItem3ColAlignLeft.RadioCheck  = false;
        menuItem3ColAlignLeft.Checked  = false;
        menuItem2ColAlignRight.RadioCheck = false;
        menuItem2ColAlignRight.Checked = false;
    }
    else if(align == HorizontalAlignment.Left)
    {
        menuItem4ColAlignCenter.Checked = false;
        menuItem4ColAlignCenter.RadioCheck = false;
        menuItem3ColAlignLeft.Checked  = true;
        menuItem3ColAlignLeft.RadioCheck  = true;
        menuItem2ColAlignRight.RadioCheck = false;
        menuItem2ColAlignRight.Checked = false;
    }

    else if(align == HorizontalAlignment.Right)
    {
        menuItem4ColAlignCenter.Checked = false;
        menuItem4ColAlignCenter.RadioCheck = false;
        menuItem3ColAlignLeft.Checked = false;
        menuItem3ColAlignLeft.RadioCheck  = false;
        menuItem2ColAlignRight.Checked = true;
        menuItem2ColAlignRight.RadioCheck = true;
    }

    // pop up the designer created context menu

    contextMenu1.Show(listView1,new Point(50,50));

}

Responding to the ContextMenu Column Add

When the user clicks on the ContextMenu's "ColumnAdd", an event is fired. Below is the event and my response in code. First, I bring up a small Dialog Box that's mounted on a group box. In that, the user can select the new column's text alignment and enter a new name.

private void menuItem6ColAdd_Click(object sender, 
    System.EventArgs e)  // Show Column Add groupBox dialog

{
    groupBox1.Visible = true;
}

When the user clicks Accept (located on the simple Dialog Box group box), the event below is triggered. All the column info selected by the user is tabulated, then placed into a ColumnHeader object named hdr. Finally, ListView.Columns.Insert(at index) is called using the clicked on column index saved previously. Here's the Accept button code.

private void button1_Click(object sender, 
      System.EventArgs e)   // Accept button for Add new Col dialog

{                    //Grab user input to set up new Column

    ColumnHeader hdr = new ColumnHeader();
    if(radioButton1.Checked)  //Set header alignment

        hdr.TextAlign = HorizontalAlignment.Left; 
        // based on radio button checks

    else if(radioButton3.Checked)
        hdr.TextAlign = HorizontalAlignment.Right;
    else
        hdr.TextAlign = HorizontalAlignment.Center;

    hdr.Text = textBox1.Text; // header column text


    hdr.Width = textBox1.Text.Length * 
      (int)listView1.Font.SizeInPoints + 10;  // Approx width necessary


    // Insert the new column

    listView1.Columns.Insert(clickedColumnIndex, hdr);

    groupBox1.Visible = false; // hide the new column dialog


}

All the other ContextMenu click responses are similar, so I won't detail them here.

A few tips when using ListView controls

  1. Your ListView control newly plopped on to your new form, won't resemble the screen shot above unless you first click on the ListView, then open its properties dialog window and change View to Details. The default is not Details so you have to do this right away. I think the default ListView control is set up for images or icons or something like that. It doesn't come out of the box looking like the example above.
  2. On the listView1 properties dialog is a property named AllowColumnReorder. The default is false. If you set this to true, the user will be able to click, then drag a column moving it from say the extreme right to the first position on the left. Try it with the demo program in which the AllowColumnRecorder is set true.
  3. There is some sort of algorithm for setting the column widths. It must be similar to "listView1.Font's size in points times the header text length". I used hdr.Width = textBox1.Text.Length * (int)listView1.Font.SizeInPoints + 10; which seems about right.
  4. I looked in vain for a way to highlight the header text of the column that the user clicked on. I couldn't find one except for references to owner draw / paint constructions that I haven't been able to fathom. Surely, there must be a simple way. Highlighting a row in ListView control is easy. Just listView.Item.BackColor = Color.whatever.

I originally thought, implementing a context menu on a ListView's column headers would be too messy. Turned out I was wrong. To me, the code is pretty straight forward. I hope this explanation helps.

History

First version released January 2004.

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