Alrighty...
I feel like I am losing my mind. I have programmed in VBA for over a decade. Custom Access Apps, Word Code, etc... I am switching over to VB.Net on some work projects, and I am hitting the WEIRDEST brick wall I have ever hit.
In my MAIN FORM... I have a combobox called cmb_References
All I want to do is ADD and CLEAR items from this combobox... but I can't !
I keep getting some error saying:
System.InvalidOperationException was caught
Message="Cross-thread operation not valid: Control 'cmb_References' accessed from a thread other than the thread it was created on."
Source="System.Windows.Forms"
StackTrace:
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.SendMessage(Int32 msg, Int32 wparam, Int32 lparam)
at System.Windows.Forms.ComboBox.NativeClear()
at System.Windows.Forms.ComboBox.ObjectCollection.ClearInternal()
at System.Windows.Forms.ComboBox.ObjectCollection.Clear()
at EngGraphicsTool.frmAttachmentTool.UpdateAttachmentList(String TargetLogicalName, Boolean LeaveThis) in C:\My Documents\Visual Studio 2005\Projects\Engineering Graphics Tool\Engineering Graphics Tool\Forms\frmAttachmentTool.vb:line 499
What the bloody heck is going on !
Here is the Sub I am trying to write...
Public Sub UpdateAttachmentList(Optional ByVal TargetLogicalName As String = "BLANK", Optional ByVal LeaveThis As Boolean = True) Try Dim MyCmb As ComboBox Dim counter As Integer, EntryText As String Dim PageType As String, PageNumber As Integer, NumberOfAttachments As Integer Dim MyActiveModel As ModelReference, MyAttachments As Attachments, MyAttachment As Attachment ' System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = FalseMyActiveModel = MyAMR
MyAttachments = MyActiveModel.Attachments
MyCmb =
Me.cmb_ReferencesMyCmb.Items.Clear()
NumberOfAttachments = IIf((LeaveThis =
True), MyAttachments.Count, MyAttachments.Count - 1) For counter = 0 To NumberOfAttachments - 1MyAttachment = MyAttachments.Item(counter + 1)
PageType = LogicalName_to_PageType(MyAttachment.LogicalName)
PageNumber = LogicalName_to_PageNumber(MyAttachment.LogicalName)
EntryText = PageType +
" Type, Page #: " + CStr(PageNumber) MyCmb.Items.Add(EntryText) Next counter Catch ex As Exception Select Case Err.Number Case 5 ' Cross-thread operation not valid: Control 'cmb_References' accessed from a thread other than the thread it was created on. End Select End Try End SubNow for those of you following along... This is an application for interacting with Microstation v8. That is the MyAttachment and such... All I want to make happen is the MyCmb.Items.Add and MyCmb.Items.Clear() and I can't for the life of me figure this out.
My background is mainly with PHP, VBA, Java ( and -script )... I have never had to deal with Threads ! Confused... please help! I have searched across this message board and found nothing to help ! I see alot about Invoking and Delegates, but nothing about simply adding an item or clearing all items from a simple combobox... ! ! ! ! !
HELP!

Cross-Threaded ComboBox???
boyapati
Hello RandomBlink
As a Guess, you are running procedures on threads other than the one that the containing form is on. This is usually done so that the interface remains responsive even during long running processes.
You can not update display data from a thread other than the thread that the dsplay control is contained on. On of the easiest ways to accomplish this in Net 2005 is to use the background worker.
Here's an example:
Imports
system.ComponentModelPublic
Class Form1 Private WithEvents MyThread As BackgroundWorker
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LoadMyThread =
New BackgroundWorker End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim Myvalue As String = "Hello World" If Not MyThread.IsBusy ThenMyThread.RunWorkerAsync(MyValue)
End If End Sub Private Sub MyThread_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles MyThread.DoWork Dim TestString As String = e.Argument '------------------------------------ 'call long running procedure here '------------------------------------e.Result = TestString
End Sub Private Sub MyThread_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles MyThread.RunWorkerCompleted '----------------------- 'return value from the 'backgrounder thread 'now you can access the 'display thread '-----------------------MsgBox(e.Result)
End SubEnd
ClassLater :)
Ibrahim
Ruurd Boeke
Hi
As already stated, it sounds like the UpdateAttachmentList method is running on a thread that differs from the thread that was used to create the combo box. This means that anytime you interact with the combo box, you need to coersce the other thread to run your code for you.
The simplest way to do this is to use the Invoke method of the control and pass it a delegate (a callback to a method). When the callback is invoked it will be running on the appropriate thread and your current thread will be suspended.
Lets try a simple example of how you might architect your solution ...
private delegate sub fn1(of T)(byval arg as T) : private delegate sub fn2(of T, T1)(byval arg1 as T, byval arg2 as T1)
private shared sub clearcombobox(byval cb as combobox)
if cb.invokerequired then
cb.invoke(new fn1(of combobox)(addressof clearcombobox), cb)
else : cb.items.clear
end if
end sub
private shared sub addcomboitem(byval cb as combobox, byval txt as string)
if cb.invokerequired then
cb.invoke(new fn2(of combobox, string)(addressof addcomboitem), cb, txt)
else : cb.items.add(txt)
end if
end sub
now instead of interacting direct with the combo box in your updateattachmentlist method, you'd call the clearcombobox method instead. When you want to add to the combo box, call the addcomboitem method and let it do the work for you.
Hope this helps, but if you need some further help, please le me know.
Richard
Gloria123
Hi,
Is cmb_References on another FORM
If so remove the Me. reference and replace it with the relevant location or try leaving it out....
I'm suprised the line>>
Dim myCmb As ComboBox 'isn't giving a squiggly line under the word ComboBox
Have you got an Imports line in your code
Dim myCmd As System.Windows.Forms.ComboBox
myCmb=ComboBox1
myCmb.Items.Add("Hello") ' works for me and so does.>>
Dim myStr As String = "there!!"
myCmb.Items.Add(myStr)
''''myCmb.Items.Clear() ' This line works too if you take the 1st four comment marks out. ;-)
Regards,
S_DS
xulei
You cannot call UI methods and properties directly from another thread than the one the form was created on. You need to use Invoke to marshall the call to the control's thread.
(If you're using .Net 2.0, consider using the BackgroundWorker class and communicate with the UI via the ProgressChanged event).
http://msdn2.microsoft.com/en-us/library/b2zk6580(vs.80).aspx
Something which may also be useful reading.
http://www.informit.com/guides/content.asp g=dotnet&seqNum=194&rl=1
If you are using just simple forms and not specifically using different threads then the following works and should mention anything about thread. It basically sets up a listbox on one form and allows you to create a different form within the same application and as long as you have a reference to the original form/control and your one the same thread then you can modify the listbox items without a problem,
Public Class Form1
Private Sub CreateASecondForm(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x As New form2
x.Form1Var = Me '//Reference to this form
x.Show()
End Sub
Private Sub BtnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnAdd.Click
Me.ListBox1.Items.Add("abc")
End Sub
End Class
Public Class Form2
Public Form1Var As Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If Form1Var IsNot Nothing Then
Form1Var.ListBox1.Items.Clear()
End If
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If Form1Var IsNot Nothing Then
Form1Var.ListBox1.Items.Add("xyz")
End If
End Sub
End Class
Sushisource
Additional Help ( heck, you offered! )
I actually do.
Two questions...
#1) The program now hangs once it has entered the clearComboBox function... or the addComboBoxItem functions and does the Invoke option. I can't figure out why
#2) I want to add column'd items to the ComboBox in question. I want to pass an itemID as well as an ITEM. That way when the user selects an item from the list I can pass the itemID to an appropriate function. However, columns are no longer part of the ComboBox as I can tell. Do you know how to do this