How can I add a context menu to a ListBoxItem?

狂风中的少年 提交于 2019-12-03 10:39:29

问题


I have a ListBox and I want to add a context menu to each item in the list. I've seen the "solution" to have the right click select an item and suppress the context menu if on white space, but this solution feels dirty.

Does anyone know a better way?


回答1:


This way the menu will pop up next to the mouse

private string _selectedMenuItem;
private readonly ContextMenuStrip collectionRoundMenuStrip;

public Form1()
{ 
    var toolStripMenuItem1 = new ToolStripMenuItem {Text = "Copy CR Name"};
    toolStripMenuItem1.Click += toolStripMenuItem1_Click;
    var toolStripMenuItem2 = new ToolStripMenuItem {Text = "Get information on CR"};
    toolStripMenuItem2.Click += toolStripMenuItem2_Click;
    collectionRoundMenuStrip = new ContextMenuStrip();
    collectionRoundMenuStrip.Items.AddRange(new ToolStripItem[] {toolStripMenuItem1, toolStripMenuItem2 });
    listBoxCollectionRounds.MouseDown += listBoxCollectionRounds_MouseDown;
}

private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
    var info = GetInfoByName(_selectedMenuItem);
   MessageBox.Show(info.Name + Environment.NewLine + info.Date);
}

private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
    Clipboard.SetText(_selectedMenuItem);
}

private void myListBox_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button != MouseButtons.Right) return;
    var index = myListBox.IndexFromPoint(e.Location);
    if (index != ListBox.NoMatches)
    {
        _selectedMenuItem = listBoxCollectionRounds.Items[index].ToString();
        collectionRoundMenuStrip.Show(Cursor.Position);
        collectionRoundMenuStrip.Visible = true;
    }
    else
    {
        collectionRoundMenuStrip.Visible = false;
    }
}



回答2:


Just to elaborate a little further to what Frans has said...Even though the ListBox owns the ContextMenuStrip, you can still customize the items in the menu strip at the time it's opening. Thus customizing it's contents based on the mouse position within the listbox.
The example below selects the item in the listbox based on a right mouse click and then customizes a context menu strip based on the item the user right-clicked on. This is a simple example but should get you going: Add a listbox to a form and add this code:

print("        #region Private Members
    private ContextMenuStrip listboxContextMenu;
    #endregion

    private void Form1_Load( object sender, EventArgs e )
    {
        //assign a contextmenustrip
        listboxContextMenu = new ContextMenuStrip();
        listboxContextMenu.Opening +=new CancelEventHandler(listboxContextMenu_Opening);
        listBox1.ContextMenuStrip = listboxContextMenu;

        //load a listbox
        for ( int i = 0; i < 100; i++ )
        {
            listBox1.Items.Add( "Item: " + i );
        }
    }

    private void listBox1_MouseDown( object sender, MouseEventArgs e )
    {
        if ( e.Button == MouseButtons.Right )
        {
            //select the item under the mouse pointer
            listBox1.SelectedIndex = listBox1.IndexFromPoint( e.Location );
            if ( listBox1.SelectedIndex != -1)
            {
                listboxContextMenu.Show();   
            }                
        }
    }

    private void listboxContextMenu_Opening( object sender, CancelEventArgs e )
    {
        //clear the menu and add custom items
        listboxContextMenu.Items.Clear();
        listboxContextMenu.Items.Add( string.Format( "Edit - {0}", listBox1.SelectedItem.ToString() ) );
    } ");

Hope that help. -Mike




回答3:


There's no other way: the context menu isn't owned by the item in the listbox but by the listbox itself. It's similar to the treeview control which also owns the context menu instead of the treenode. So whenever an item in the listbox is selected, set the context menu of the listbox according to the selected item.




回答4:


And Here it is My Solution :

listBox_Usernames.ContextMenuStrip = contextMenuStripRemove;
listBox_Usernames.MouseUp += new MouseEventHandler(listBox_Usernames_MouseUp);

void listBox_Usernames_MouseUp(object sender, MouseEventArgs e)
{
    int index = listBox_Usernames.IndexFromPoint(e.Location);
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
    {
        if (index != ListBox.NoMatches)
        {
            if (listBox_Usernames.SelectedIndex == index)
            {
                listBox_Usernames.ContextMenuStrip.Visible = true;
            }
            else
            {
                listBox_Usernames.ContextMenuStrip.Visible = false;
            }
        }
        else
        {
            listBox_Usernames.ContextMenuStrip.Visible = false;
        }
    }
    else
    {
        listBox_Usernames.ContextMenuStrip.Visible = false;
    }
}



回答5:


In XAML it shows like this:

<ListBox>
    <ListBox.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Add User..."/>
            <MenuItem Header="Edit..."/>
            <MenuItem Header="Disable"/>
        </ContextMenu>
    </ListBox.ContextMenu>
</ListBox>



回答6:


If its just a question of enabling or disabling context menu items, it might be more efficient to only do it when the context menu is launched rather than every time the list box selection changes:

myListBox.ContextMenu.Popup += new EventHandler(myContextPopupHandler);


private void myContextPopupHandler(Object sender, System.EventArgs e)
{
    if (SelectedItem != null)
    {
        ContextMenu.MenuItems[1].Enabled = true;
        ContextMenu.MenuItems[2].Enabled = true;
    }
    else
    {
        ContextMenu.MenuItems[1].Enabled = false;
        ContextMenu.MenuItems[2].Enabled = false;
    }
}



回答7:


this one is best...

using System.Windows.Forms;

ContextMenuStrip menu;

this.menu.Items.AddRange(new ToolStripItem[] { this.menuItem });
this.listBox.MouseUp += new MouseEventHandler(this.mouse_RightClick);

private void mouse_RightClick(object sender, MouseEventArgs e)
{
    int index = this.listBox.IndexFromPoint(e.Location);
    if (index != ListBox.NoMatches)
    {
        menu.Visible = true;
    }
    else
    {
        menu.Visible = false;
    }
}



回答8:


In one line of code (more for binding):

var datasource = new BindingList<string>( new List<string>( new string[] { "item1" } ) );
listbox.DataSource = datasource ;
listbox.ContextMenu = new ContextMenu(
    new MenuItem[] { 
        new MenuItem("Delete", 
            new EventHandler( (s,ev) => 
            datasource.Remove(listbox.SelectedItem.ToString())
        )
    ) 
});

private void buttonAdd_Click(object sender, EventArgs e)
{
    datasource.Add( textBox.Text );
}   



回答9:


//Create and Initialize the contextMenuStrip component
contextMenuStrip_ListaAulas = new ContextMenuStrip();

//Adding an Item
contextMenuStrip_ListaAulas.Items.Add("Modificar");

//Binding the contextMenuStrip with the ListBox
listBox_Aulas.ContextMenuStrip = contextMenuStrip_ListaAulas;

//The solution below 
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
    //select the item under the mouse pointer
    listBox_Aulas.SelectedIndex = listBox_Aulas.IndexFromPoint(e.Location);

    //if the selected index is an item, binding the context MenuStrip with the listBox
    if (listBox_Aulas.SelectedIndex != -1)
    {
         listBox_Aulas.ContextMenuStrip = contextMenuStrip_ListaAulas;  
    }
    //else, untie the contextMenuStrip to the listBox 
    else
    {
         listBox_Aulas.ContextMenuStrip = null;
    }
}



回答10:


I do like this, this works great and fast for me.

private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
    {
        if (Listbox.SelectedItem == null)
            e.Cancel = true;
    }


来源:https://stackoverflow.com/questions/376910/how-can-i-add-a-context-menu-to-a-listboxitem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!