Adding a ContextMenuStrip to several ListViews

It is hard enough to remember my opinions, without also remembering my reasons for them! — Friedrich Nietzsche



Adding a ContextMenuStrip to a single ListView is quite simple – just drag’n'drop stuff in the Forms Designer it seems. Not everything that seems simple actually is that simple though. When trying to perform some action on a specified ListViewItem things can quickly become more complicated. Even more so when working with several ListViews but only one ContextMenuStrip that is supposed to do all the work. In the following example I will show how to deal with the small problems one will come across when trying to implement those features.

Lets create a new Windows Forms Application called ListViewContextMenuStripExample. In the Form Designer add 2 ListViews and a ContextMenuStrip, called listView1, listView2 and contextMenuStrip1 respectively. We need to assign the ContextMenuStrip to the ListViews, add a context menu item, set the ListViews to details view, add the ListView column headers and add some items to the listviews. Last but not least we need to create an event handler that fires whenever the specified context menu item was clicked. To do so modify “Form1.cs” with the changes in the forms constructor, like in the code snippet below:

using System;
using System.Windows.Forms;

namespace ListViewContextMenuStripExample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // assign ContextMenuStrip to both ListViews
            listView1.ContextMenuStrip = contextMenuStrip1;
            listView2.ContextMenuStrip = contextMenuStrip1;

            // add a context menu item
            ToolStripItem webpageToolStripMenuItem;
            webpageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            contextMenuStrip1.Items.Add(webpageToolStripMenuItem);
            webpageToolStripMenuItem.Text = "open webpage in browser";

            // set ListViews to Details view
            listView1.View = View.Details;
            listView2.View = View.Details;

            // add a single column to each list view
            listView1.Columns.Add("ListViewHeader1", listView1.Width-4);
            listView2.Columns.Add("ListViewheader2", listView2.Width-4);

            // populate the list view with some items
            listView1.Items.Add("http://www.sascha-hennig.de");
            listView1.Items.Add("http://www.microsoft.com");
            listView2.Items.Add("http://www.sascha-hennig.de/csharp/");
            listView2.Items.Add("http://www.mler-community.de");

            // add the event handler
            webpageToolStripMenuItem.Click +=
                new System.EventHandler(this.webpageToolStripMenuItem_Click);
        }

        // the event handler
        private void webpageToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }
    }
}

You can obviously do a lot of the above by just using the Forms Designer, the way its done here is done for clarity. Hit Ctrl+F5 to run the application and see the context menu in action when right clicking on either of the ListViews.

The more problematic part: figuring out what ListViewItem actually sent the event. The object that webpageToolStripMenuItem_Click refers to is the ContextMenuStrip, not the – or one of the – ListView(s). The answer is pretty simple actually. Knowing that the sender-object is actually of the type ToolStripMenuItem, we create a new object of that type and assign “sender” to it. Now we need to get its owner, which should be the ContextMenuStrip. Then we need to get the control that the mouse was over when we right clicked. The property “SourceControl” will give us exactly what we need.

Now that we have a reference to our ListView we can easily access its items. To get the exact item that was pointed to by the mouse pointer when the right mouse click happened, we get the index of the selected item – which incidentally should be the item we need (as right clicking an item will select it). This approach will certainly only work for cases where the ListView does not allow for selecting more than one item. Nevertheless it should be simply to adapt for when one needs to perform an action on multiple items. Noteworthy might be that we need to check weather any item at all was actually selected, else – if that is not the case, the application will throw an exeption if passing that part of the code. Here how the event handling membercould look like:

        // the event handler
        private void webpageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // get the object that sent the event (the ContextMenuItem)
            ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
            // get the owner of the ToolStripMenuItem (the ContextMenuStrip)
            ContextMenuStrip cms = tsmi.Owner as ContextMenuStrip;
            // get the control that received the click event (one of the ListViews)
            ListView ctrl = cms.SourceControl as ListView;
            // check if any item is selected
            if (ctrl.SelectedItems.Count > 0)
            {
                // if so, open webpage (or in our case just a messagebox)
                MessageBox.Show(ctrl.Items[ctrl.SelectedIndices[0]].Text);
            }
        }

This should give you the basis for implementing ContextMenuStrips in your own applications. The example is certainly improvable. If having a ListViewItem selected and right clicking on the column header will open the context menu and if the context menu item is clicked the event handler member will perform its magic on the still selected item. That should not be the functionality we want. To get around this issue you might want to try and catch the click event of the ListView, check for the position of the mouse and if it is positioned in the column header cancel the click. As it is always possible to extend an example, but I am rather striving for simplicity, I will leave this implementation up to the reader.

[dm]6[/dm]

VN:F [1.9.18_1163]
Rating: 5.0/5 (2 votes cast)
Adding a ContextMenuStrip to several ListViews, 5.0 out of 5 based on 2 ratings
Friday, February 20th, 2009 at 20:28
131 visits
No comments yet.

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>