32

I know how to make a contextMenu that pops up when I right click on a listView, what I want is for it to pop up when I right click on an item. I am trying to make a chat server and client, and now... Now I want to view client info when I right click on a connected client's item.

How can I do this?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Daaksin
  • 834
  • 3
  • 13
  • 28

8 Answers8

82
private void listView1_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        var focusedItem = listView1.FocusedItem;
        if (focusedItem != null && focusedItem.Bounds.Contains(e.Location))
        {
            contextMenuStrip1.Show(Cursor.Position);
        }
    } 
}

You can put connected client information in the contextMenuStrip1. and when you right click on a item, you can show the information from that contextMenuStrip1.

David Sherret
  • 101,669
  • 28
  • 188
  • 178
Rashedul.Rubel
  • 3,446
  • 25
  • 36
  • 2
    I thought this should be the default behavior, but oh well. It really is a simple, neat piece of code. – Joel Feb 10 '14 at 19:52
  • Thanks! BTW == true is not required. Can be just : if (listView1.FocusedItem.Bounds.Contains(e.Location)) – Pradeep Oct 23 '15 at 00:05
  • yes, you can write Boolean condition without == here. but it is a way although. – Rashedul.Rubel Oct 23 '15 at 04:49
  • 6
    Put additional condition to avoid an exception if the list have no items if (LV_Input.FocusedItem != null && LV_Input.FocusedItem.Bounds.Contains(e.Location) == true) – al000y Dec 31 '15 at 19:28
8

You are going to have to use the ListViews Context Menu, but change it according to the ListView Item you right click on.

private void listView1_MouseDown(object sender, MouseEventArgs e)
{
    bool match = false;

    if (e.Button == System.Windows.Forms.MouseButtons.Right)
    {
        foreach (ListViewItem item in listView1.Items)
        {
            if (item.Bounds.Contains(new Point(e.X, e.Y)))
            {
                MenuItem[] mi = new MenuItem[] { new MenuItem("Hello"), new MenuItem("World"), new MenuItem(item.Name) };
                listView1.ContextMenu = new ContextMenu(mi);
                match = true;
                break;
            }
        }
        if (match)
        {
            listView1.ContextMenu.Show(listView1, new Point(e.X, e.Y));
        }
        else
        {
            //Show listViews context menu
        }

    }

}
Mark Hall
  • 53,938
  • 9
  • 94
  • 111
4

You can trigger MouseDown or MouseUp event of ListView in which if MouseButton.Right then grab the selected Item by using ListView.Hittest and give the Context menu related to that Selected Item.

For more clear info you can go through this link

Community
  • 1
  • 1
Mr_Green
  • 40,727
  • 45
  • 159
  • 271
4

Fully solution

  • Pops up when user right click on a item in a listView.
  • Avoid an exception if the list have no items.
  • If an item was selected, display Delete and Edit options.

enter image description here

Code:

private void Form1_Load(object sender, EventArgs e)
{
    listView1.MouseUp += new MouseEventHandler(listView1_MouseClick);

}

private void listView1_MouseClick(object sender, MouseEventArgs e)
{
    string id = "xxx";//extra value

    if (e.Button == MouseButtons.Right)
    {
        if (listView1.FocusedItem != null && listView1.FocusedItem.Bounds.Contains(e.Location) == true)
        {
            ContextMenu m = new ContextMenu();
            MenuItem cashMenuItem = new MenuItem("編輯");
            cashMenuItem.Click += delegate (object sender2, EventArgs e2) {
                ActionClick(sender, e, id);
            };// your action here 
            m.MenuItems.Add(cashMenuItem);

            MenuItem cashMenuItem2 = new MenuItem("-");
            m.MenuItems.Add(cashMenuItem2);

            MenuItem delMenuItem = new MenuItem("刪除");
            delMenuItem.Click += delegate (object sender2, EventArgs e2) {
                DelectAction(sender, e, id);
            };// your action here
            m.MenuItems.Add(delMenuItem);

            m.Show(listView1, new Point(e.X, e.Y));

        }
    }
}

private void DelectAction(object sender, MouseEventArgs e, string id)
{
    ListView ListViewControl = sender as ListView;
    foreach (ListViewItem eachItem in ListViewControl.SelectedItems)
    {
        // you can use this idea to get the ListView header's name is 'Id' before delete
        Console.WriteLine(GetTextByHeaderAndIndex(ListViewControl, "Id", eachItem.Index) );
        ListViewControl.Items.Remove(eachItem);
    }
}

private void ActionClick(object sender, MouseEventArgs e, string id)
{
    //id is extra value when you need or delete it
    ListView ListViewControl = sender as ListView;
    foreach (ListViewItem tmpLstView in ListViewControl.SelectedItems)
    {
        Console.WriteLine(tmpLstView.Text);
    }

}

public static string GetTextByHeaderAndIndex(ListView listViewControl, string headerName, int index)
{
    int headerIndex = -1;
    foreach (ColumnHeader header in listViewControl.Columns)
    {
        if (header.Name == headerName)
        {
            headerIndex = header.Index;
            break;
        }
    }
    if (headerIndex > -1)
    {
        return listViewControl.Items[index].SubItems[headerIndex].Text;
    }
    return null;
}
kkasp
  • 113
  • 1
  • 9
2
    private void contextMenuStripExport_Opening(object sender, System.ComponentModel.CancelEventArgs e)
    {
        if (exportview.SelectedItems.Count <= 0)
        {
            uploadToolStripMenuItem.Visible = false;
            exportToolStripMenuItem.Visible = false;
        }
        else
        {
            uploadToolStripMenuItem.Visible = true;
            exportToolStripMenuItem.Visible = true;
        }
    }
emalware
  • 73
  • 1
  • 9
  • Could you please add a little explanation what is new about your solution. This is quite an old thread an has an accepted answer – slfan Oct 27 '18 at 05:41
  • 1
    The biggest difference is that all of the other answers assume that opening a context menu is hard linked to Right clicking, when in fact that's just the majority of cases, but not all of them. This one does whatever Windows does and piggybacks on the opening event itself. – Eduard Dumitru Jul 03 '23 at 06:40
0

The topic is quite old, but I'll leave my solution for reference.

In xaml ListView definition put your context menu:

<ListView Name="m_list" >
    <ListView.ContextMenu>
        <ContextMenu>
            <MenuItem Header="menuItem1" Click="ContextMenuItem1Clicked" />
            <MenuItem Header="menuItem2" Click="ContextMenuItem2Clicked" />
        </ContextMenu>
    </ListView.ContextMenu>
...
</ListView>

Now, in the code, define two event handlers that will fire up on clicking respective menu item:

private void ContextMenuItem1Clicked(object sender, RoutedEventArgs e)
{
    // handle the event for the selected ListViewItem accessing it by
    ListViewItem selected_lvi = this.m_list.SelectedItem as ListViewItem;
}

private void ContextMenuItem2Clicked(object sender, RoutedEventArgs e)
{
    // handle the event for the selected ListViewItem accessing it by
    ListViewItem selected_lvi = this.m_list.SelectedItem as ListViewItem;
}

ListView can accommodate objects, which means that the selected_lvi can be of type of your object. Just cast is to proper type.

I hope this helps.

Best regards,

Mike

Mike
  • 1,225
  • 10
  • 21
  • 6
    This seems like WPF solution, while the question is about WinForms. – Suma Jul 19 '13 at 10:09
  • 1
    @Suma seems you're right, i didn't even notice the winforms tag in the original question. Anyhow this actually helped me ^^ – CyberFox Aug 22 '16 at 05:23
0

I've found a new solution that doesn't rely on mouse event handlers. The ContextMenu has a "Popup" event handler.

On popup, I add the relevant menu items I need depending on my context.

Example :

private MenuItem[] standardMenuItems;
private MenuItem[] selectedMenuItems;

public SomePanel() {
    InitializeComponent();

    // These are list of menu items (name / callback) that will be
    // chosen depending on some context
    standardMenuItems = new MenuItem[] { new MenuItem("New", OnNew) };
    selectedMenuItems = new MenuItem[] { new MenuItem("Delete", OnDelete), new MenuItem("Edit", OnEdit) };

    ContextMenu contextMenu = new ContextMenu();

    // begin with "standard items"
    contextMenu.MenuItems.AddRange(standardMenuItems);
    listview.ContextMenu = contextMenu;

    // add the popup handler
    contextMenu.Popup += OnMenuPopup;
}

// Called right before the menu comes up
private void OnMenuPopup(object sender, EventArgs e) {
    ContextMenu menu = sender as ContextMenu;
    if (menu == null)
        return;

    // If an item was selected, display Delete and Edit options
    if (listview.SelectedItems.Count > 0) {
        menu.MenuItems.Clear();
        menu.MenuItems.AddRange(selectedMenuItems);
    }

    // Else display only the New option
    else {
        menu.MenuItems.Clear();
        menu.MenuItems.AddRange(standardMenuItems);
    }
}

I'm not fluent enough in C# and Winforms to be sure there are no drawbacks to this technique, but it's an alternative to relying on mouse events (what if / does the context menu can appear on other keyboard or mouse event ?)

brainsandwich
  • 472
  • 3
  • 10
-1

Using DevExpress 20.2 Core... Winforms. This is similar to handling a menu item in a GridView.

Private WithEvents _menuViewLabelitem As MenuItem
    Private Sub lvShipTracking_MouseClick(sender As Object, e As MouseEventArgs) Handles lvShipTracking.MouseClick

    If e.Button = MouseButtons.Right Then

        If lvShipTracking.FocusedItem IsNot Nothing AndAlso lvShipTracking.FocusedItem.Bounds.Contains(e.Location) = True Then
            Dim m As ContextMenu = New ContextMenu()
            _menuViewLabelitem = New MenuItem("View Label")

            AddHandler Click, AddressOf Handle_ViewLabel

            m.MenuItems.Add(_menuViewLabelitem)
            m.Show(lvShipTracking, New Point(e.X, e.Y))
        End If
    End If

End Sub

Private Sub Handle_ViewLabel(sender As Object, e As EventArgs) Handles _menuViewLabelitem.Click
    MsgBox("it worked!")
End Sub