Selecting 1 Tool Strip Menu Item at any one time - vb.net

I have a Tool strip menu with 4 options.
The options are degrees of screen rotation. (0, 90, 180, 270)
I am trying to select only 1 of these and keep it selected.
When I choose one then another, both are ticked (selected).
I have searched and found some solutions but only this works for me.
I have used the click event for each option to clear the ones not chosen like below.
Private Sub DegreesToolStripMenuItem6_Click(sender As Object, e As EventArgs) Handles DegreesToolStripMenuItem6.Click
DegreesToolStripMenuItem6.Checked = True
DegreesToolStripMenuItem7.Checked = False
DegreesToolStripMenuItem8.Checked = False
DegreesToolStripMenuItem9.Checked = False
End Sub
This sub is in my code 4 times to make it work but i'm sure there must be a cleaner, easier way to do this.
I have found online some other solutions but I can't seem to make it work, this one kind of makes sense like it should work but I can't figure it out
Private Sub DegreesToolStripMenuItem6_CheckedChanged(sender As Object, e As EventArgs) Handles DegreesToolStripMenuItem6.CheckedChanged, _
DegreesToolStripMenuItem7.CheckedChanged, _
DegreesToolStripMenuItem8.CheckedChanged, _
DegreesToolStripMenuItem9.CheckedChanged
Dim currentItem As ToolStripMenuItem = TryCast(sender, ToolStripMenuItem)
If currentItem IsNot Nothing AndAlso currentItem.Checked Then
Dim menu As ContextMenuStrip = TryCast(currentItem.Owner, ContextMenuStrip)
If menu IsNot Nothing Then
'The current item has just been checked so uncheck all other items on the same context menu strip.
For Each item As ToolStripMenuItem In menu.Items
If item IsNot currentItem Then
item.Checked = False
End If
Next item
End If
End If
End Sub
the toolstrip menu reads like this
-PreferedRotationToolStripMenuItem-DegreesToolStripMenuItem6
DegreesToolStripMenuItem7
DegreesToolStripMenuItem8
DegreesToolStripMenuItem9
Thanks for your time and looking forward to any help you guys can give.

Set CheckOnClick to True for each menu item, which I'm guessing you already have. This code worked for me:
Private Sub ToolStripMenuItems_CheckedChanged(sender As Object, e As EventArgs) Handles DegreesToolStripMenuItem9.CheckedChanged,
DegreesToolStripMenuItem8.CheckedChanged,
DegreesToolStripMenuItem7.CheckedChanged,
DegreesToolStripMenuItem6.CheckedChanged
Dim currentMenuItem = DirectCast(sender, ToolStripMenuItem)
If currentMenuItem.Checked Then
Dim menu = DirectCast(currentMenuItem.Owner, ContextMenuStrip)
For Each menuItem In menu.items.Cast(Of ToolStripMenuItem)
menuItem.Checked = menuItem Is currentMenuItem
Next
End If
End Sub
Here's a slight variation that avoids checking the already checked current item:
Private Sub ToolStripMenuItems_CheckedChanged(sender As Object, e As EventArgs) Handles DegreesToolStripMenuItem9.CheckedChanged,
DegreesToolStripMenuItem8.CheckedChanged,
DegreesToolStripMenuItem7.CheckedChanged,
DegreesToolStripMenuItem6.CheckedChanged
Dim currentMenuItem = DirectCast(sender, ToolStripMenuItem)
If currentMenuItem.Checked Then
Dim menu = DirectCast(currentMenuItem.Owner, ContextMenuStrip)
For Each menuItem In menu.Items.Cast(Of ToolStripMenuItem).Except({currentMenuItem})
menuItem.Checked = False
Next
End If
End Sub
The code above works if you have added the items to a ContextMenuStrip. If you have added them directly to an item on a MenuStrip then change this:
Dim menu = DirectCast(currentMenuItem.Owner, ContextMenuStrip)
to this:
Dim menu = DirectCast(currentMenuItem.Owner, ToolStripDropDownMenu)

Related

Creating/Deleting Objects via Checking if Toggles in CheckListBox in VB.Net

I am playing around with some CheckedListItems in CheckBoxes and i am having issues with determining when a specific checked Product is checked and/or unchecked via its index position.
I know from MsgBox debugging that if i select either Product Allpurpose Cleaner or Cleaning Wipes it calls the MsgBoxes of both methods despite me attempting using logic to only execute for that specific Product. Somehow it thinks I have selected both items?
So essentially i am trying to do this:
If item zero in CheckedListBox is checked
Call conform menu to get desired amountand then come back to ordering menu.
ElseIF item zero in CheckedListBox is unchecked
Remove it from the current order.
This would essentially be rinse and repeat for all items in my CheckedListBox. I suspect VB.NET is causing my code to 'fall through' and it thinks all of the items i select are the same despite my attempts at preventing this.
May i please have some thoughts on this?
Thank you.
Private Sub CleaningProductsList_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CleaningProductsList.SelectedIndexChanged
Dim allPurposeCleaner = New AllPurposeCleaner()
Dim cleaningCloths = New cleaningCloths()
' If checked.
If CleaningProductsList.GetItemChecked(0) = True Then
isChecked = True
Me.Hide()
' MsgBox("All Purpose Cleaner Selected")
AmountMenue.setGivenProduct(allPurposeCleaner)
AmountMenue.Show()
' If unchecked.
ElseIf CleaningProductsList.GetItemChecked(0) = False Then
isChecked = False
' MsgBox("All Purpose Cleaner UnSelected ")
MsgBox(CleaningProductsList.GetItemChecked(0).ToString + " ALLPURPOSE UNCHECKED")
AmountMenue.removedGivenProduct(allPurposeCleaner)
End If
' If checked.
If CleaningProductsList.GetItemChecked(1) = True Then
Me.Hide()
AmountMenue.setGivenProduct(cleaningCloths)
MsgBox("cleaning cloths Selected ")
AmountMenue.Show()
' If unchecked.
ElseIf CleaningProductsList.GetItemChecked(1) = False And CleaningProductsList.CheckOnClick = False Then
MsgBox("cleaning cloths UnSelected ")
MsgBox(CleaningProductsList.GetItemChecked(2).ToString + " Cleaning Cloths UNCHECKED")
isChecked = False
AmountMenue.removedGivenProduct(cleaningCloths)
End If
End Sub
Here's an example of how you determine changes in a CheckedListBox:
Private checkedIndexes As New List(Of Integer)
Private checkedItems As New List(Of String)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CheckedListBox1.Items.AddRange({"First", "Second", "Third", "Fourth", "Fifth"})
End Sub
Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
If e.NewValue = CheckState.Checked Then
'An item is being checked.
checkedIndexes.Add(e.Index)
checkedItems.Add(CStr(CheckedListBox1.Items(e.Index)))
Else
'An item is being unchecked.
checkedIndexes.Remove(e.Index)
checkedItems.Remove(CStr(CheckedListBox1.Items(e.Index)))
End If
Label1.Text = $"Checked indexes: {String.Join(", ", checkedIndexes)}"
Label2.Text = $"Checked items: {String.Join(", ", checkedItems)}"
End Sub
The e parameter tells you what item is changing, via the Index property, and what it is changing from and to, via the CurrentValue and NewValue properties.
If you want to get a full list of checked items in that event handler, because the event is raised before the change is finalised, you need to start with the list provided by the control and then add or remove the current item:
Dim checkedItems = CheckedListBox1.CheckedItems.Cast(Of String)().ToList()
If e.NewValue = CheckState.Checked Then
checkedItems.Add(CStr(CheckedListBox1.Items(e.Index)))
Else
checkedItems.Remove(CStr(CheckedListBox1.Items(e.Index)))
End If
'Use checkedItems here.

Disable listview item in vb.net

I am trying to disable item (row) in my list view but its seem there no option like .enable = false and I tried to find anything to get my item to by disable but visible. Is there anything like that? If the user is allowed to select it then the item is enabled else it's visible but not enabled.
I have a table in the database that admin will fill it in which the user can view the window or not, so I want the user to able to see it and if not allowed to view it then its disable.
This only works if MultiSelect is set to False and the .Tag property is set for every item. (Yes or No).
Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
If Not ListView1.SelectedItems.Count = 0 Then
Dim item As ListViewItem = ListView1.SelectedItems(0)
If item.Tag.ToString = "No" Then
item.Selected = False
End If
End If
End Sub
As per # jmcilhinney , The following code should work with MultiSelect = True. I tried to access the last item added to the collection but it seems that the SelectedItems collection is ordered the same as the order the items appear in the ListView; not as expected the last item added would be last in the collection..
Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
If Not ListView1.SelectedItems.Count = 0 Then
For Each item As ListViewItem In ListView1.SelectedItems
If item.Tag.ToString = "No" Then
item.Selected = False
End If
Next
End If
End Sub

Change the tooltip text when selecting item in listview

I have a listview containing the source addresses of files (from user system) and the destination addresses (two columns, multilpe selection = false).
Since the source addresses might be quite long like:
d:\root\branch1\branch2\branch3\branch4\myfile.dat
the first column shows just:
d:\ ... \myfile.dat
The real path is stored in the ListViewItem.Tag
I want to have a tooltip showing the whole path every time the user clicks (or changes) the selected item. I came out with this:
Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
For Each locItem As ListViewItem In ListView1.SelectedItems
With ToolTip1
.RemoveAll()
.SetToolTip(ListView1, locItem.Tag)
End With
Next
End Sub
Now, the tooltip does change, but it always skip one selection. That is:
selecting item 1: tooltip shows correctly
selecting item 2: tooltip don't show
selecting item 3: tooltip shows correctly
selecting item 5: tooltip don't show
selecting item 2: tooltip shows correctly (selection went back to item 2 which didn't show the 1st time)
Any idea?
PS: I am using Visual Studio Community 2015
PPS: I also need to have the View property set to View.Details (to show both columns and headers), so setting ShowItemToolTip = True does not work
CURRENT SOLUTION
I found a workaround, destroying and recreating the tooltip control. Now the tooltip shows correctly on every item:
Private myTooltip As ToolTip
Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
If myTooltip IsNot Nothing Then myTooltip.Dispose()
myTooltip = New ToolTip
For Each locItem As ListViewItem In ListView1.SelectedItems
myTooltip.SetToolTip(ListView1, locItem.Tag)
Next
End Sub
I'm still baffled about the skipping in the first approach.
ListView has a property called ShowItemToolTips (https://msdn.microsoft.com/en-us/library/system.windows.forms.listview.showitemtooltips(v=vs.110).aspx). You can set that to true and then set the ToolTipText property of the ListViewItems to the long path.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
ListView1.ShowItemToolTips = True
Dim lvi1 As New ListViewItem With {.Text = "d:\..\myFile.dat", .Tag = "d:\myLongPath\myFile.dat", .ToolTipText = .Tag}
Dim lvi2 As New ListViewItem With {.Text = "d:\..\myFile2.dat", .Tag = "d:\myLongPath\myFile2.dat", .ToolTipText = .Tag}
ListView1.Items.Add(lvi1)
ListView1.Items.Add(lvi2)
End Sub

Button Array - how to pass a parameter to shared handler

I have a bit of code where i have a dynamically created array or buttons with staff pictures on them, as well as the staff's name. I've added one handler to handle any button click from any of the buttons. where i am stuck is, if you look at the code below, it all works fine, and if you click any of the buttons you get the "aha" test message. but i want the name of the staff clicked on (so btnArray(i).Text) to be passed to the handler for further processing. I tried adding a ByVal parameter to the handler but that caused an error. what's the correct way to do this? As i said, the code below works for me, i just am at a loss as to how to add the extra functionality.
Dim btnArray(staffcount) As System.Windows.Forms.Button
For i As Integer = 1 To staffcount - 1
btnArray(i) = New System.Windows.Forms.Button
btnArray(i).Visible = True
btnArray(i).Width = 80
btnArray(i).Height = 101
btnArray(i).BackgroundImage = Image.FromFile(picloc(i))
btnArray(i).BackgroundImageLayout = ImageLayout.Stretch
btnArray(i).Text = staffname(i)
Dim who As String
who = btnArray(i).Text
AddHandler btnArray(i).Click, AddressOf Me.theButton_Click
btnArray(i).ForeColor = Color.White
btnArray(i).TextAlign = ContentAlignment.BottomCenter
Dim fnt As Font
fnt = btnArray(i).Font
btnArray(i).Font = New Font(fnt.Name, 10, FontStyle.Bold)
FlowLayoutPanel1.Controls.Add(btnArray(i))
Next i
End Sub
Private Sub theButton_Click()
MsgBox("aha")
End Sub
First, correct the signature of your shared handler.
Private Sub theButton_Click(sender As Object, e As EventArgs)
End Sub
Once that is done getting the text of the button clicked is a simple matter.
Private Sub theButton_Click(sender As Object, e As EventArgs)
Dim textOfButtonClicked As String = DirectCast(sender, Button).Text
MessageBox.Show(textOfButtonClicked)
End Sub
The sender is the button that was clicked. Since signatures use objects for the sender the DirectCast 'changes' it to button and you then can access the .Text property of the button.
If there are more manipulations you want to perform on the clicked button you could do it this way
Private Sub theButton_Click(sender As Object, e As EventArgs)
Dim whBtn As Button = DirectCast(sender, Button) ' get reference to button clicked
Dim textOfButtonClicked As String = whBtn.Text
MessageBox.Show(textOfButtonClicked)
'e.g. change the color
whBtn.BackColor = Color.LightYellow
End Sub

Programmatically setting properties of controls on tab pages of a tabcontrol

I am working with a tabcontrol on which I create page one with the designer. I am creating new tab pages with controls on the pages programmatically. On each page is a several panels, each with two radiobuttons (one yes,another no). There is a panel nested inside the first panel with its visible property set to false. If the user selects yes, I want the nested panel's visible property set to true which will reveal several more radiobuttons from which they must make more choices.
My problem is in changing the nested panel's property on any page other than page one.. I can detect the radiobuttons, but I can't seem to find a way to make the nested panel visible.
Public Class ControlProgram
Dim pageindx as integer
Private Sub btnAddPrgm1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddPrgm1.Click
Dim newTab As New TabPage()
pageindx = (TabControl1.TabPages.Count + 1)
newTab.Text = "Step " & pageindx
'define fill panel controls
Dim newpnlFill As New Panel
Dim newlblFill As New Label
Dim newFillY As New RadioButton
AddHandler newFillY.CheckedChanged, AddressOf CheckforCheckedChanged
Dim newFillN As New RadioButton
AddHandler newFillN.CheckedChanged, AddressOf CheckforCheckedChanged
'add fill panel controls
With newTab.Controls
.Add(newpnlFill)
With newpnlFill
.Location = New System.Drawing.Point(6, 6)
.Size = New System.Drawing.Size(171, 137)
.BorderStyle = BorderStyle.FixedSingle
.Controls.Add(newlblFill)
With newlblFill
.Name = "Fill"
.Text = "Fill ?"
.Font = New Font(newlblFill.Font, FontStyle.Bold)
.Location = New Drawing.Point(5, 3)
End With
.Controls.Add(newFillY)
With newFillY
.Name = "FillY"
.Text = "Yes"
.Location = New Drawing.Point(23, 28)
.Size = New System.Drawing.Size(43, 17)
End With
.Controls.Add(newFillN)
With newFillN
.Name = "FillN"
.Text = "No"
.Location = New Drawing.Point(88, 28)
.Size = New System.Drawing.Size(39, 17)
End With
.Controls.Add(newpnlFill2)
With newpnlFill2
.Location = New System.Drawing.Point(2, 60)
.Size = New System.Drawing.Size(164, 68)
.BorderStyle = BorderStyle.FixedSingle
.Visible = False
End With
End With
End With
Private Sub CheckforCheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs)
If TypeOf sender Is RadioButton Then
bEvent = CType(sender, RadioButton).Name
End If
End Sub
End Class
I have since figured out a solution to my delima, using your suggestions as a starting point.
I added a few varribles:
Dim rb as Control
Dim bEvent as String
Dim booFillY as Boolean
Dim booFillN as Boolean
I also added the TabControl
TabControl1.TabPages.Add(newTab)
I also made these changes :
Private Sub CheckforCheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs)
If TypeOf sender Is RadioButton Then
rb = sender
bEvent = CType(sender, RadioButton).Name
If bEvent = "FillY" Then
Dim newpnlFill2 As Panel = rb.Parent.Controls(3)
newpnlFill2.Visible = True
End If
If bEvent = "FillN" Then
Dim newpnlFill2 As Panel = rb.Parent.Controls(3)
newpnlFill2.Visible = False
End If
End If
End Sub
Now I can make the nested panel(newpnlFill2) visible or not visible by cicking the Yes or No radiobuttons on any of the tab pages created.
thanks for your help. I doubt I would have ever gotten there on my own.
Might not be quite what you were looking for, but should be helpful get you where you need to go.
When I create an application, I like to build a list of all the controls for a given page in the load event so I can access them at any point. This is helpful because WinForms can be very picky about showing you child controls within a tabpage or groupbox, etc.
'Declare this variable within the class for your form (whatever)
Public arrControlsRecursive As New List(Of Control)
'method to recursively check all controls and build to array
Private Sub BuildControlsArrayRecursive(ByVal InControl As Control)
For Each con As Control In InControl.Controls
If con.Controls.Count > 0 Then
BuildControlsArrayRecursive(con)
End If
If TypeOf con Is Control Then
arrControlsRecursive.Add(con)
End If
Next
End Sub
'Call from MyBase.Load Event
BuildControlsArrayRecursive(Form1)
You can also just assemble a list of all tabs, for example, by changing the If statement to Is TypeOf con Is TabPage
Now you can loop through this collection or query it with LINQ. Find a single control by calling the first or single method. Cast to the type you want and do anything to any control anywhere within your form.
I don't really understand what you want to access, you first talk about
changing the nested panel's property on any page other than page one
So I assume you want to access to the other tabs, then, you talk about:
I can't seem to find a way to make the panel visible
Anyway, here's the two solutions:
Access other panels:
Private Sub CheckforCheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs)
If TypeOf sender Is RadioButton Then
bEvent = CType(sender, RadioButton).Name '**Where is "bEvent" declared??**
Dim newpnlFill2 as Panel = bEvent.Parent.Controls(3), Panel)
newpnlFill2.Visible = bEvent.Checked
End If
End Sub
You access to Parent that will be newpnlFill, then access to Controls(3) that it should be newpnlFill2.
Access other tabs:
Private Sub CheckforCheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs)
If TypeOf sender Is RadioButton Then
bEvent = CType(sender, RadioButton).Name '**Where is "bEvent" declared??**
Dim TabControl as TabControl = bEvent.Parent.Parent.Parent, TabControl)
'Then, you can access all of the other tabs with:
'TabControl.TabPages(n)
End If
End Sub
This assume that somewhere you add your newTab to a TabControl.
I see that you never add newTab to any TabControl, so you'll never see it..
The first Parent will be newpnlFill, the second one will reference to newTab and the last one is the TabControl that hold the Tab.
Anyway, it's something really gross, cause it assumes that your Tab is always created in this manner. For example, if you will add another panel before newpnlFill, it will not be the 4th Control in the Panel anymore, so you need to change you access code.
My advice is to create your own UserControl that inherit from TabPage, in this way you can create private variables that will always reference to the Panels you want to change. Moreover, the btnAddPrgm1_Click event will be much more clear, moving the build of the page in your class constructor.
Something like:
Private Sub btnAddPrgm1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddPrgm1.Click
Dim newTab As New MyTabPage()
pageindx = (TabControl1.TabPages.Count + 1)
newTab.Text = "Step " & pageindx
TabControl1.TabPages.Add(newTab)
End Sub