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)
{
clickedColumnIndex = e.Column;
HorizontalAlignment align =
listView1.Columns[clickedColumnIndex].TextAlign;
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;
}
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)
{
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)
{
ColumnHeader hdr = new ColumnHeader();
if(radioButton1.Checked)
hdr.TextAlign = HorizontalAlignment.Left;
else if(radioButton3.Checked)
hdr.TextAlign = HorizontalAlignment.Right;
else
hdr.TextAlign = HorizontalAlignment.Center;
hdr.Text = textBox1.Text;
hdr.Width = textBox1.Text.Length *
(int)listView1.Font.SizeInPoints + 10;
listView1.Columns.Insert(clickedColumnIndex, hdr);
groupBox1.Visible = false;
}
All the other ContextMenu
click responses are similar, so I won't detail them here.
A few tips when using ListView controls
- 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.
- 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
.
- 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.
- 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.