ListBox en ContextMenuStrip

Status
Niet open voor verdere reacties.

Pim15

Gebruiker
Lid geworden
18 mrt 2012
Berichten
257
Ik heb in mijn programmaatje een ListBox staan. Als ik in de ListBox op een item klik, wil ik een ContextMenuStrip laten zien. Maar alleen als ik erop sta met mijn muis (en het item heb geselecteerd). Als ik het item dus heb geselecteerd en ik klik met de rechtermuisknop op een leeg deel van de ListBox, moet er dus niks verschijnen. Ik heb even op het internet gezocht, maar niet echt iets bruikbaars kunnen vinden. Veel is namelijk in C# en mijn Engels is ook niet zo goed. Ik hoop dat iemand mij uit de brand kan helpen.

Pim
 
Laatst bewerkt:
Je contextmenu heeft een opening event, hierin kun je een Cancel argument op true zetten als de listbox.SelectedItems.Count < 1 is.

Of je kunt hier bepaalde buttons verbergen zoals de een 'edit'/'remove' button zodat de 'add' button alleen zichtbaar is.
 
Ik was vergeten erbij te zetten, dat het de bedoeling is dat het volledig in code is. Ik zal het nogmaals zo goed mogelijk proberen te omschrijven. Ik heb een ListBox met daarin waardes die bij het opstarten uit een .txt worden ingelezen. Als je met de muis op het item staat, en op de rechtermuisknop drukt, moet er een ContextMenuStrip verschijnen. Als je het item hebt geselecteerd, maar er dus niet met de muis bovenop staat, en dan op de rechtermuisknop drukt, moet er GEEN ContextMenuStrip verschijnen. En als je het item dus hebt geselecteerd EN er met de muis bovenopstaat en dan op de rechtermuisnop drukt, moet er ook een ContextMenuStrip verschijnen. Ik hoop dat het nu een beetje duidelijk is. Als dat niet het geval is, schroom je niet om te reageren!

Pim
 
De code is in C# maar het is zo simpel dat het wel duidelijk is wat er gebeurt.

Een private boolean die bijhoud of het context menu gecanceled moet worden of niet (als er geen selectie is).

Bij het mouse down even haal je de index op waar op wordt geklikt, als deze -1 is dan is er nergens op geklikt en zet je de cancel variable op true
(en ik zet het selected item als index omdat met een right click het item normaal nog niet wordt geselecteerd)

voor het openen van je context menu, cancel je deze als de cancel variable op true was gezet, anders je menu aanpassen waar nodig en dan komt het tevoorschijn.

voorbeeld aanpassing is de selected item text gebruiken in de context menu item

[CPP]private bool _cancelContextMenu = true;

private void lstItems_MouseDown(object sender, MouseEventArgs e)
{
var index = lstItems.IndexFromPoint(e.X, e.Y);

_cancelContextMenu = index == -1;

lstItems.SelectedIndex = index;
}

private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
e.Cancel = _cancelContextMenu;

if (!e.Cancel)
{
//context menu item
cmiEdit.Text = string.Format("Edit '{0}'", lstItems.SelectedItem);
}
}[/CPP]
 
Ik heb zitten puzzelen, maar er gebeurt helemaal niks... Dit is de code waar het in moet:
Code:
    Private Sub ListBox1_MouseClick(sender As Object, e As MouseEventArgs) Handles ListBox1.MouseClick
        Dim path As String = "Toebehoren.schak"
        Dim streamReader As New System.IO.StreamReader(path)
        '
        Do Until streamReader.EndOfStream
            ' Reading Line by Line :
            Dim line As String = streamReader.ReadLine()
            Dim fabrikantafkorting As String = line.Split(";")(0)
            Dim artikelnummer As Integer = line.Split(";")(1)
            Dim productnaam As String = line.Split(";")(2)
            Dim fabrikant As String
            If fabrikantafkorting = 1 Then
                fabrikant = "Fabrikant1"
            ElseIf fabrikantafkorting = 2 Then
                fabrikant = "Fabrikant2"
            End If
            ' Controleer of de gevonden lijn overeenkomt met het geselecteerde ListBox item
            If fabrikant & " " & artikelnummer & " (" & productnaam & ")" = ListBox1.SelectedItem Then
                Dim uitvoering As String = line.Split(";")(3)
                Dim uitvoeringaanwezig As Boolean
                If uitvoering = Nothing Then
                    uitvoeringaanwezig = False
                Else
                    uitvoeringaanwezig = True
                End If
                If uitvoeringaanwezig = True Then
                    Dim uitvoeringarray As Array = Split(uitvoering)
                    Dim contextmenustrip As New ContextMenuStrip
                    [COLOR="#FF0000"]' Vanaf hier moet de ContextMenuStrip verschijnen[/COLOR]
                End If
            End If
        Loop
        streamReader.Close()
        '
    End Sub
Ik weet namelijk ook niet of de openingssub van jouw code mijn ContextMenusStrip vindt. Dus misschien kan jij er even naar kijken? Dit gaat mij namelijk een beetje de pet te boven.

Pim

[EDIT]Zo ziet Toebehoren.schak eruit:
1;7130;stekker (oud model);bruin,groen,grijs,rood,geel
1;7130;moffen (oud model);bruin,groen,grijs,rood,geel
1;71400;stekker (nieuw model);bruin,groen,grijs,rood,geel
1;71400;moffen (nieuw model);bruin,groen,grijs,rood,geel
1;71421;moffen bruin (nieuw model);
1;71422;moffen geel (nieuw model);
1;71423;moffen groen (nieuw model);
1;71424;moffen oranje (nieuw model);
1;71425;moffen rood (nieuw model);
1;71426;moffen grijs (nieuw model);
Dingen uit de vierde kolom moeten in de ContextMenuStrip verschijnen.[/EDIT]
 
Laatst bewerkt:
Ik heb eerst een product class gemaakt en een aparte methode gemaakt om producten te laden, want dit hoef je maar 1x te doen neem ik aan.
(is altijd mogelijk om alsnog nieuw te laden)

- Een getproducts method haalt deze op en vult de listbox (nadat de producten in een variable lijst zijn opgeslagen).
- Het mouse down event voor de listbox is hetzelfde als hiervoor
- Het context menu is gewoon in de designer aan de listbox gekoppeld en de items daarin worden opgebouwd door de BuildContextMenuForSelectedItem methode.
- Ik heb ook nog even het click event van de context menu's erbij gedaan om het compleet te maken. (messagebox bij contextmenuitem click)


Op het form:

ListBox lstItems
Button btnLoadProducts
ContextMenuStrip productContextMenu

(contextmenustrip aan listbox koppelen in designer)

in code: _productsFilename = "products.txt" <- bestandsnaam aanpassen


Heb het in C# gemaakt en omgezet met dit: hoopt dat het werkt (voor mij wel)

'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: @telerik
'Facebook: facebook.com/telerik
'=======================================================

Code:
Public Partial Class Form1
	Inherits Form
	Private _productsFilename As String
	Private _products As List(Of Product)
	Private _cancelContextMenu As Boolean = False

	Public Sub New()
		InitializeComponent()

		_productsFilename = "products.txt"
		_products = New List(Of Product)()
	End Sub

	Private Sub GetProducts()
		'read file and create products
		Using reader = New StreamReader(_productsFilename)
			_products.Clear()

			While Not reader.EndOfStream
				Dim productLine = reader.ReadLine()

				If productLine IsNot Nothing Then
					Dim product = New Product()

					Dim parts = productLine.Split(";"C)

					product.CompanyId = parts(0)
					product.Id = parts(1)
					product.Name = parts(2)

					If parts(3) <> "" Then
						product.Models = parts(3).Split(","C)
					End If

					_products.Add(product)
				End If
			End While
		End Using

		'populate listbox
		lstItems.Items.Clear()
		For Each product As var In _products
			lstItems.Items.Add(product)
		Next

		'MessageBox.Show(string.Format("{0} products loaded", _products.Count));
	End Sub
	Private Sub BuildContextMenuForSelectedItem(selectedProduct As Product)
		productContextMenu.Items.Clear()

		If selectedProduct Is Nothing Then
			Return
		End If

		If selectedProduct.Models IsNot Nothing Then
			For Each model As var In selectedProduct.Models
				Dim menu = New ToolStripMenuItem(model) With { _
					Key .Tag = selectedProduct _
				}
				'add the product to the tag to reference it easy
				AddHandler menu.Click, AddressOf productContextMenu_Click

				productContextMenu.Items.Add(menu)
			Next
		End If
	End Sub

	Private Sub productContextMenu_Click(sender As Object, e As EventArgs)
		Dim menuItem = DirectCast(sender, ToolStripMenuItem)

		Dim product = TryCast(menuItem.Tag, Product)

		If product Is Nothing Then
			MessageBox.Show(String.Format("You clicked the {0} model of an unknown product.", menuItem.Text))
		Else
			MessageBox.Show(String.Format("You clicked the {0} model of {1}.", menuItem.Text, product.Name))
		End If
	End Sub
	Private Sub productContextMenu_Opening(sender As Object, e As CancelEventArgs)
		e.Cancel = _cancelContextMenu

		Dim selectedProduct = TryCast(lstItems.SelectedItem, Product)

		'if the product doesn't have models, also cancel it
		If selectedProduct IsNot Nothing Then
			If selectedProduct.Models Is Nothing Then
				e.Cancel = True
			End If
		End If

		If Not e.Cancel Then
			BuildContextMenuForSelectedItem(selectedProduct)
		End If
	End Sub
	Private Sub lstItems_MouseDown(sender As Object, e As MouseEventArgs)
		Dim index = lstItems.IndexFromPoint(e.X, e.Y)

		_cancelContextMenu = index = -1

		lstItems.SelectedIndex = index
		'-1 deselects item
	End Sub
	Private Sub btnLoadProducts_Click(sender As Object, e As EventArgs)
		GetProducts()
	End Sub
End Class

Code:
Public Class Product
	Public Property Id() As String
		Get
			Return m_Id
		End Get
		Set
			m_Id = Value
		End Set
	End Property
	Private m_Id As String
	Public Property Name() As String
		Get
			Return m_Name
		End Get
		Set
			m_Name = Value
		End Set
	End Property
	Private m_Name As String
	Public Property CompanyId() As String
		Get
			Return m_CompanyId
		End Get
		Set
			m_CompanyId = Value
		End Set
	End Property
	Private m_CompanyId As String
	Public Property Models() As String()
		Get
			Return m_Models
		End Get
		Set
			m_Models = Value
		End Set
	End Property
	Private m_Models As String()

	Public Overrides Function ToString() As String
		Return String.Format("{0} - {1}", Id, Name)
	End Function
End Class
 
Hallo Bloodshed,

Heel erg bedankt voor deze code. Ik heb er veel vertrouwen in dat deze werkt, maar er zijn een paar rode lijntjes.
1. Var wordt niet herkent als iets.
2. Bij dit:
Code:
Dim menu = New ToolStripMenuItem(model) With { _
					Key.Tag = selectedProduct _
				}
wordt Key niet als iets herkent.
3. Bij dit:
Code:
Private Sub productContextMenu_Opening(sender As Object, e As CancelEventArgs)
wordt CancelEventArgs niet herkent.
Zou je hier misschien nog even naar kunnen kijken?

Alvast bedankt,
Pim
 
Ik denk dat het zo ongeveer wel zal werken.

1.

Code:
For Each product As var In _products
	lstItems.Items.Add(product)
Next

>>

Code:
For Each product As Product In _products
	lstItems.Items.Add(product)
Next



2.

Code:
Dim menu = New ToolStripMenuItem(model) With { _
					Key.Tag = selectedProduct _
				}

>>

Code:
Dim menu = New ToolStripMenuItem(model)
menu.Tag = selectedProduct



3.

Code:
Private Sub productContextMenu_Opening(sender As Object, e As CancelEventArgs)

>>

Code:
Private Sub productContextMenu_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles productContextMenu.Opening
 
Die fouten zijn opgelost, maar ik zag er nog een. Bij deze code:
Code:
            For Each product As Product In _products
                ListBox1.Items.Add(product)
                Dim menu = New ToolStripMenuItem([COLOR="#FF0000"]model[/COLOR])
                menu.Tag = selectedProduct
                'add the product to the tag to reference it easy
                AddHandler menu.[COLOR="#FF0000"]Click[/COLOR], AddressOf ContextMenuStrip1_Click

                ContextMenuStrip1.Items.Add(menu)
            Next
wordt model niet herkent en Click. Zou je daar ook nog naar kunnen kijken?

Pim
 
Dit is niet de code die ik er had staan, 'model' komt van een loop door de product.Models

Code:
Private Sub BuildContextMenuForSelectedItem(selectedProduct As Product)
	productContextMenu.Items.Clear()

	If selectedProduct Is Nothing Then
		Return
	End If

	If selectedProduct.Models IsNot Nothing Then
		For Each model As var In selectedProduct.Models
			Dim menu = New ToolStripMenuItem(model)
			menu.Tag = selectedProduct
			
			'add the product to the tag to reference it easy
			AddHandler menu.Click, AddressOf productContextMenu_Click

			productContextMenu.Items.Add(menu)
		Next
	End If
End Sub

Als deze addhandler niet werkt kun je hem even commenten, om het programma wel te laten werken. Ik denk dat je wel zo in VB de click eraan hangt.
 
Dat werkt. Dankjewel. Alleen ik bedenk me dat het handiger is als het met de linkermuisknop gebeurt. Dat lukt mij alleen niet. Kun je daar de code voor geven?

Pim
 
Dit zou toch moeten werken bij linker klik. Het mouse down event is bij linker- middel- en rechtermuis knop voor zover ik weet.
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan