I'm trying to clear items from a listbox that currently appear as child nodes in a treeview. I've come up with storing the child nodes in an array(which works) then thought I would loop through and remove the listbox item if it appears in the array (basically the treenodes are added from double clicking the treeview and are placed under a dated parent node).
When I run the code I get the following error message on the final Next
List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.
I know this is to do with the For Each loop however I'm struggling as a novice to work it out.
Dim ndes As New ArrayList
Dim no As TreeNode
For Each no In tvProgress.Nodes
Dim CNode As TreeNode
For Each CNode In no.Nodes
ndes.Add(CNode.Text)
Next
Next
Dim ditem As Object
For Each ditem In lstPlanned.Items
If ndes.Contains(ditem) Then
lstPlanned.Items.Remove(ditem)
End If
Next
You need a diff loop:
For i As Integer = (lstPlanned.Items.Count - 1) To 0 Step -1
If ndes.Contains(lstPlanned.Items(i)) Then
lstPlanned.Items.Remove(lstPlanned.Items(i))
Exit For
End If
Next
Related
I am making a To Do program. I have a checked list box there. I want to make every checked item deleted automatically. Here's the code that I am using to check if checked:
For i = 0 To CheckedListBox1.Items.Count - 1
If CheckedListBox1.GetItemChecked(i) Then
Else
End If
Next
How can I do that? Thanks
To remove Items from your ListBox, you can save items to be removed in your loop and then to delete it for example :
Dim itemsToRemove As New List(Of Object)
For i = 0 To CheckedListBox1.Items.Count - 1
If CheckedListBox1.GetItemChecked(i) Then
itemsToRemove.Add(CheckedListBox1.Items(i))
End If
Next
For Each item As Object in itemsToRemove
CheckedListBox1.Items.Remove(item)
Next
If you loop backwards then removing an item doesn't affect the part of the list you have yet to check
For i = CheckedListBox1.Items.Count - 1 to 0 Step -1
If CheckedListBox1.GetItemChecked(i) Then
CheckedListBox1.Items.RemoveAt(i)
End If
Next
This won't prevent the cross thread exception you're getting; for that we really need to know why you're accessing this Control from a thread other than the thread that created it
Although I'm reasonable experienced VBA developer, I have not had the need to use class modules or collections but thought this may be my opportunity to extend my knowledge.
In an application I have a number of forms which all have the same functionality and I now need to increase that functionality. Towards that, I am trying to reorder a collection in a class module, but get an error 91 - object variable or with block not set. The collection is created when I assign events to controls. The original code I obtained from here (Many thanks mwolfe) VBA - getting name of the label in mousemove event
and has been adapted to Access. The assignments of events works well and all the events work providing I am only doing something with that control such as change a background color, change size or location on the form.
The problem comes when I want to reorder it in the collection - with a view to having an impact on location in the form. However I am unable to access the collection itself in the first place.
The below is my latest attempt and the error occurs in the collcount Get indicated by asterisks (right at the bottom of the code block). I am using Count as a test. Once I understand what I am doing wrong I should be able to manipulate it as required.
mLabelColl returns a correct count before leaving the LabelsToTrack function, but is then not found in any other function.
As you will see from the commented out debug statements, I have tried making mLabelColl Private and Dim in the top declaration, using 'Debug.Print mLabelColl.Count' in the mousedown event and trying to create a different class to store the list of labels.
I feel I am missing something pretty simple but I'm at a loss as to what - can someone please put me out of my misery
Option Compare Database
Option Explicit
'weMouseMove class module:
Private WithEvents mLbl As Access.Label
Public mLabelColl As Collection
'Dim LblList as clLabels
Function LabelsToTrack(ParamArray labels() As Variant)
Set mLabelColl = New Collection 'assign a pointer
Dim i As Integer
For i = LBound(labels) To UBound(labels)
'Set mLabelColl = New Collection events not assigned if set here
Dim LblToTrack As weMouseMove 'needs to be declared here - why?
Set LblToTrack = New weMouseMove 'assign a pointer
Dim lbl As Access.Label
Set lbl = labels(i)
LblToTrack.TrackLabel lbl
mLabelColl.Add LblToTrack 'add to mlabelcoll collection
'Set LblList as New clLabels
'LblList.addLabel lbl
Next i
Debug.Print mLabelColl.Count 'returns correct number
Debug.Print dsform.countcoll '1 - incorrect
End Function
Sub TrackLabel(lbl As Access.Label)
Set mLbl = lbl
End Sub
Private Sub mLbl_MouseDown(Button As Integer, Shift As Integer, x As Single, Y As Single)
Dim tLbl As Access.Label
'Debug.Print LblList.Count 'Compile error - Expected function or variable (Despite Count being an option
'Debug.Print mLabelColl.Count 'error 91
'Debug.Print LblList.CountLbls 'error 91
Debug.Print collCount
End Sub
Property Get collCount() As Integer
*collCount = mLabelColl.Count* 'error 91
End Property
In order to have all the weMouseMove objects reference the same collection in their mLabelColl pointer, a single line can achieve it:
LblToTrack.TrackLabel lbl
mLabelColl.Add LblToTrack
Set LblToTrack.mLabelColl = mLabelColl ' <-- Add this line.
But please be aware that this leads to a circular reference between the collection and its contained objects, a problem that is known to be a source of memory leaks, but this should not be an important issue in this case.
Not sure if my title makes much sense, so I will try to explain my question here. So basically I am expanding my program by allowing things to be customized within it.
Say for example I do this: I click on File -> Options, and a new form is opened with tabs. I have different settings that you can toggle via dropdown box and checkboxes. Now once a user sets the settings they want, or don't want, they click on a button that says either "OK" or "Cancel".
What is the method to saving these settings, or reverting back to the original settings? Do you save via txt file, or is this a default function within a certain line of code?
UPDATE:
So I fixed my previous issue. Now I am having another with the saves. The saves are working good, but I want to use them in selecting my CheckListBox Collection range and also have that range load on start as well. so these are the 2 things that I have been using to do so, that results in adding to the previous, set, collection.
Working for RNG:
Dim rand As New Random()
Dim winners = Enumerable.Range(1, My.Settings.numberSetting).OrderBy(Function(r) rand.Next()).Take(5).ToArray()
Not working for Onload CheckListBox:
Me.LotteryNumbers.Items.Add(1, My.Settings.numberSetting)
If I remove the 1 from Me.LotteryNumbers.Items.Add, the result is this:
This ought not compile:
LotteryNumbers.Items.Add(1, My.Settings.numberSetting)
The overload which takes a second argument expect a Boolean to set the item added to Checked or not. One way is to add items in a loop:
Dim maxNums = My.Settings.numberSetting
' make sure it is empty
clb.Items.Clear()
For n As Int32 = 1 To maxNums
clb.Items.Add(n.ToString)
Next
I don't like using items in Settings as variables, so it grabs the current value to use. Another way uses AddRange:
clb.Items.AddRange(Enumerable.Range(1, maxNums).Select(Function(s) s.ToString()).ToArray())
Items is an collection of Object, so the Select converts to string to add them.
NEVER ORDER BY RANDOM.NEXT()
Mostly you get lucky, but it's not guaranteed. It's only a matter of time before that code blows up on you at run time. The longer the sequence to be sorted, the more likely you are to get an exception.
What you should do instead is implement a Fisher-Yates sort method:
Private rand As New Random()
Public Function Shuffle(Of T)(ByVal items As IList(Of T)) As IList(Of T)
For i As Integer = items.Count - 1 To 1 Step -1
Dim j As Integer = rand.Next(i + 1)
Dim temp As T= items(i)
items(i) = items(j)
items(j) = temp
Next
Return items
End Function
Solution for the working code to update and save checklistbox box count.
Private Sub OptionOkButton_Click(sender As Object, e As EventArgs) Handles OptionOkButton.Click
Main.LotteryNumbers.Items.Clear()
My.Settings.numberSetting = CInt(NumberCombo.Text)
Dim maxNum = My.Settings.numberSetting
Main.LotteryNumbers.Items.AddRange(Enumerable.Range(1, maxNum).Select(Function(s) s.ToString()).ToArray())
My.Settings.Save()
Me.Close()
End Sub
Hi I know this may sound a little weird but I am trying to have a master list that contains other lists of controls. Here is what I have so far.
'Create master list of control lists. Each member of this list will be a list containing one rows worth of controls
Dim masterList As New List(Of List(Of Control))
Dim rowList As New List(Of Control)
For Each Control As Control In flpExceptionControls.Controls
rowList.Add(Control)
If flpExceptionControls.GetFlowBreak(Control) = True Then
masterList.Add(rowList)
rowList.Clear()
End If
Next
For Each row As List(Of Control) In masterList
MsgBox(row.Count.ToString)
Next
The message box is showing that each of those lists have a count of 0, but I know it is adding all the controls to those objects because it shows it when I step through the code. I'm guessing I am just not accessing the list objects contained in the master list correctly.
Any suggestions would be greatly appreciated.
Your problem is here:
If flpExceptionControls.GetFlowBreak(Control) = True Then
masterList.Add(rowList)
rowList.Clear()
End If
You are clearing the contents of the same list, which you are then adding some new items to, and clearing again, and adding the same reference to the master list. Essentially; all of your items in masterList are the same, empty list.
You need to create a new sub-list for each. Don't clear any lists.
Dim rowList As New List(Of Control)
For Each Control As Control In flpExceptionControls.Controls
rowList.Add(Control)
If flpExceptionControls.GetFlowBreak(Control) = True Then
masterList.Add(rowList)
rowList = New List(Of Control)
End If
Next
How do I get the SuspendLayout and ResumeLayout to work correctly in regards to a listview. I have added these lines of code before and after I have added the items, yet each item is still being displayed as I add each item.
thanks
My code:
Dim x As Integer
Dim startTick As Integer = Environment.TickCount
lstFiles.SuspendLayout()
For x = 0 To UBound(cacheListArray)
If cacheListArray(x) Like "*.txt" Then
lstFiles.Items.Add(cacheListArray(x))
End If
Next
lstFiles.ResumeLayout()
MsgBox(Environment.TickCount - startTick)
I am adding 2000 items. This takes 7 seconds. I was told that it should be a lot shorter than that. Is that correct?
New code:
Dim ListViewItemArray(-1) As ListViewItem
ReDim Preserve ListViewItemArray(UBound(ListViewItemArray) + 1)
ListViewItemArray(UBound(ListViewItemArray)).Text = file.Name
ListViewItemArray(UBound(ListViewItemArray)).SubItems.Add(file.FullName)
ListViewItemArray(UBound(ListViewItemArray)).SubItems.Add(file.Length)
ListViewItemArray(UBound(ListViewItemArray)).SubItems.Add(file.CreationTime)
ListViewItemArray(UBound(ListViewItemArray)).SubItems.Add(file.LastWriteTime)
ListViewItemArray(UBound(ListViewItemArray)).SubItems.Add(file.LastAccessTime)
lstFiles.Items.AddRange(ListViewItemArray)
Nothing is being added. What have I done incorrectly?
You are using the wrong method. The Suspend/ResumeLayout() methods are only appropriate for container controls whose child controls you want to move around without them getting repainted while you are doing so. You never give ListView any child controls.
Use the Begin/EndUpdate() methods instead.