|
web
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Manipulating controls created by another threadThe problem just is: In those articles they're always working with only one class. But what if I have more than one? Here's my program: Public Class Form1 Delegate Sub DisplayStatus(ByVal msg As String) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MyWorker As New Worker Dim t As New Threading.Thread(AddressOf MyWorker.counter) t.Start() End Sub Public Sub Status(ByVal msg As String) TextBox1.Text = msg End Sub End Class Public Class Worker Public Sub counter() Dim i As Integer For i = 0 To 10000 Form1.TextBox1.BeginInvoke(New Form1.DisplayStatus(AddressOf Form1.Status), New Object() {i.ToString}) Next End Sub End Class When I try to run it I get the error "Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde." Roughly translated to "Invoke or begininvoke can only be run when the windows handle has been created". Can anyone tell me what I have to do? I managed to understand the other stuff with invoke, but I have no idea how to get that handle... Pass in the for instance when you create the worker, i.e. :
Dim MyWorker As New Worker ( Me ) then invoke on the instance. Also make sure Button1 is not returning a "dialogresult". If it is, it might destroy the form when it is clicked which will result in the handle being unavailable. I'm sorry, but don't quite get it. Could you paste your lines into my source?
I guess you mean something like this Public Class Form1 Delegate Sub DisplayStatus(ByVal msg As String) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MyWorker As New Worker Dim t As New Threading.Thread(AddressOf MyWorker.counter) t.Start() End Sub Public Sub Status(ByVal msg As String) TextBox1.Text = msg End Sub End Class Public Class Worker Public Sub counter() Dim i As Integer For i = 0 To 10000 Form1.TextBox1.BeginInvoke(New Form1.DisplayStatus(AddressOf Form1.Status), New Object() {i.ToString}) Next End Sub End Class But how can the constructor of the Worker-Class take that parameter? And how can it be used? This seems to be the same problem, but they haven't found a solution, yet:
http://groups.google.de/group/microsoft.public.dotnet.framework.windowsforms.controls/browse_thread/thread/a8da95805f8bc6ef/38bd026d36a33fa8%2338bd026d36a33fa8 Here, also as branco says ;) Please note that if you close the form before
the thread has completed, you will get the handle error. I have introduced a delay in the thread so you can see it in operation - and am using "Invoke" rather than "BeginInvoke". Public Class Form1 Delegate Sub DisplayStatus(ByVal msg As String) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MyWorker As New Worker(Me) Dim t As New Threading.Thread(AddressOf MyWorker.counter) t.Start() End Sub Public Sub Status(ByVal msg As String) TextBox1.Text = msg End Sub End Class Public Class Worker Private m_Form As Form1 Public Sub New(ByVal theForm As Form1) m_Form = theForm End Sub Public Sub counter() Dim i As Integer Dim theDelegate As New Form1.DisplayStatus(AddressOf m_Form.Status) For i = 0 To 10000 m_Form.Invoke(theDelegate, New Object() {i.ToString}) Threading.Thread.Sleep(100) Next End Sub End Class Show quoteHide quote "Jens" <J***@discussions.microsoft.com> wrote in message news:2768AEED-A9A1-4E17-A46A-1B50E215E92F@microsoft.com... > This seems to be the same problem, but they haven't found a solution, yet: > http://groups.google.de/group/microsoft.public.dotnet.framework.windowsforms.controls/browse_thread/thread/a8da95805f8bc6ef/38bd026d36a33fa8%2338bd026d36a33fa8 Jens wrote:
<snip> Show quoteHide quote > Public Class Worker <snip>> > Public Sub counter() > Dim i As Integer > For i = 0 To 10000 > Form1.TextBox1.BeginInvoke(New Form1.DisplayStatus(AddressOf > Form1.Status), New Object() {i.ToString}) > > Next > End Sub > > End Class > > When I try to run it I get the error "Invoke oder BeginInvoke kann für ein > Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde." > Roughly translated to "Invoke or begininvoke can only be run when the > windows handle has been created". The problem with the code above is that you're apparently trying to use a default instance of Form1 -- a *bad* practice. Pass a reference to the actual instance of the form and use that. Something in the likes of: <aircode> > Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As _ MyWorker.Form1 = Me> System.EventArgs) Handles Button1.Click > Dim MyWorker As New Worker > Dim t As New Threading.Thread(AddressOf MyWorker.counter) Public Form As Form1> t.Start() > End Sub > Public Class Worker </aircode> It also seems to me that you don't need to create 10000 (actually 10001) new instances of the delegate. Just one would suffice: > Public Sub counter() Dim Ds As New Form1.DisplayStatus(AddressOf Form1.Status)> Dim i As Integer Form1.TextBox1.BeginInvoke(Ds, New Object() {i.ToString})> For i = 0 To 10000 > Next HTH.Regards, Branco. So, I've tried to integrate your proposals, but still the same error msg:
Public Class Form1 Delegate Sub DisplayStatus(ByVal msg As String) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MyWorker As New Worker MyWorker.Form = Me Dim t As New Threading.Thread(AddressOf MyWorker.counter) t.Start() End Sub Public Sub Status(ByVal msg As String) TextBox1.Text = msg End Sub End Class Public Class Worker Public Form As Form1 Public Sub counter() Dim i As Integer Dim DS As New Form1.DisplayStatus(AddressOf Form1.Status) For i = 0 To 10000 Form1.TextBox1.BeginInvoke(DS, New Object() {i.ToString}) Next End Sub End Class Jens wrote:
> So, I've tried to integrate your proposals, but still the same error msg: <snip>> Public Class Worker <snip>> Public Form As Form1 > > Public Sub counter() > Dim i As Integer > Dim DS As New Form1.DisplayStatus(AddressOf Form1.Status) > > For i = 0 To 10000 > Form1.TextBox1.BeginInvoke(DS, New Object() {i.ToString}) This last line should reference the Form variable, not Form1 (I noticed just now that there's an error in the "aircode" of my previous message, sorry about that). Also, you may want to follow Robinson's suggestion, and use Invoke() instead of BeginInvoke(), for the first will work synchronously -- that is, it will block until the form processes the message. This may or may not be what you want... That said, the line above would then read: Form.Invoke(DS, New Object() {i.ToString}) Notice that Form is the variable you declared in your Worker class. HTH. Regards, Branco. Oops!
I just noticed the following: > Public Sub counter() The above line should obviously read:> Dim i As Integer > Dim DS As New Form1.DisplayStatus(AddressOf Form1.Status) Dim DS As New Form1.DisplayStatus(AddressOf Form.Status) At this point I should rename this thread to "The hurdles caused by a misplaced '1' in aircode and similar helping devices", but the actual issue is "Always follow your best practices even when aircoding." (which I didn't) =) Seriously, take a look at Robinson's example, it does the right thing. Regards, Branco. NOW IT WORKS :-)
Here's the "final" code (actually it's just the beginning) Public Class Form1 Delegate Sub DisplayStatus(ByVal msg As String) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MyWorker As New Worker(Me) Dim t As New Threading.Thread(AddressOf MyWorker.counter) t.Start() End Sub Public Sub Status(ByVal msg As String) TextBox1.Text = msg End Sub End Class Public Class Worker Public Form As Form1 Public Sub New(ByVal myForm As Form1) Form = myForm End Sub Public Sub counter() Dim i As Integer Dim DS As New Form1.DisplayStatus(AddressOf Form.Status) For i = 0 To 10000 Form.TextBox1.BeginInvoke(DS, New Object() {i.ToString}) Next End Sub End Class Thanks a lot to both of you. I doubt I would have found a solution on my own... The improvements will help. The program is supposed to read a file and make some statistics with it. Since this process may take a while I want the user to have a status bar, which I couldn't change until now. Again, thanks a lot!
Estimates on money lost because of VB.NET
Connection string in app.config for class library Re: Great Reasons Not To Learn VB.NET - PART 1 time difference Strings and Resource Files Help!! Domain privs to run standalone .Net EXE from domain account? Can't maximize Help referencing control backgorund image Great Reasons To Learn VB.NET - PART 1 COM error in vb.net2 |
|||||||||||||||||||||||