Home All Groups Group Topic Archive Search About
Author
17 Jul 2006 3:01 PM
Simon Verona
I think I'm doing this wrong :

I have a class with a public shared method such as follows:

   public shared sub myFunction
        dim frm as new myFrm
        dim t as new Threading.Thread(Addressof  myFrm.myShowDialog
        t.start
   end sub

In the frm - the myShowDialog just does a "me.showdialog".

The idea is that this function will display a form, but then return control
back to the calling routine immediately without waiting for the form to be
closed.

It works, but I've had several reports of the form that is displayed
"crashing" as it is being displayed, with random errors (I've not got a
sample) or the whole application just disappearing (without error).

Can anybody assist, either by confirming or otherwise that what I'm doing is
reasonable, or perhaps letting me know a better way.

Regards
Simon

ps Previously posted by mistake to vb.controls group.

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011



--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011

Author
17 Jul 2006 3:23 PM
iwdu15
well im kinda curious on why it looks like your attempting to show another
form on a different thread....are you meaning to put the form on another
thread, and if so why?
--
-iwdu15
Author
17 Jul 2006 3:35 PM
Simon Verona
Good question...

Maybe if I explain the application....

I have a main form, which displays a list of entries.   The application
allows you to click on an entry to open a form to view/update the details of
that entry.

However, I wanted to allow multiple entries to be displayed together.

Also, I wanted to encapsulate the display of the form within a class (it is
used in many parts of the application as well, so I felt it would be
easier).

If I display the form without creating the thread, the form dies as soon as
the subroutine exits back to the main form (IIRC!), so I came up with this
as a workaround.   It also seemed to have the affect of making the
application seem to run smoother (though that could just be me).  If I don't
create the thread and just use showdialog, then the original form is blocked
until it returns.

I don't know why it should be causing a problem, but if there is a better
way of acheiving the same thing without creating the thread then I'm up for
it!

Regards
Simon



--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011

Show quoteHide quote
"iwdu15" <jmmgoalsteratyahoodotcom> wrote in message
news:C1079914-7732-4C59-A82A-2EFD1FE9AD01@microsoft.com...
> well im kinda curious on why it looks like your attempting to show another
> form on a different thread....are you meaning to put the form on another
> thread, and if so why?
> --
> -iwdu15
Author
17 Jul 2006 3:44 PM
iwdu15
well, if you wan to do it that way, then make sure our thread safe. Threads
can only access objects they create, for instance your Form1 cannot access
things on your other thread's form and vice versa, keep that in mind. To
access methods on other threads, use the threads Invoke method, dont call the
method directly. Keeping that in mind, there wouldnt be a need to call
"ShowDialog" and show the form on a new thread....i dont know if that would
cause issues or not, so your best bet would be calling "Show", not
"ShowDialog"
--
-iwdu15
Author
17 Jul 2006 3:39 PM
iwdu15
if you want to show a new form on a different thread, then the new thread
must then create the form object:

Private Delegate Sub delNewThread

Private Sub btnNewThread_Click(...)

Dim x as New delNewThread(AddressOf CreateNewFormThreadBegin)

Me.Invoke(x)

End Sub

Private Sub CreateNewFormThreadBegin()

Dim frm as New Form2

frm.ShowDialog()

End Sub


that will create a new form on a different thread then show it
--
-iwdu15
Author
17 Jul 2006 3:30 PM
Larry Lard
Simon Verona wrote:
Show quoteHide quote
> I think I'm doing this wrong :
>
> I have a class with a public shared method such as follows:
>
>    public shared sub myFunction
>         dim frm as new myFrm
>         dim t as new Threading.Thread(Addressof  myFrm.myShowDialog
>         t.start
>    end sub
>
> In the frm - the myShowDialog just does a "me.showdialog".
>
> The idea is that this function will display a form, but then return control
> back to the calling routine immediately without waiting for the form to be
> closed.

If this is what you want, why not just .Show (rather than .ShowDialog)
the form? Anyway...

>
> It works, but I've had several reports of the form that is displayed
> "crashing" as it is being displayed, with random errors (I've not got a
> sample) or the whole application just disappearing (without error).
>
> Can anybody assist, either by confirming or otherwise that what I'm doing is
> reasonable, or perhaps letting me know a better way.

I think you are falling foul of the rule whereby UI elements cannot be
safely interacted with from threads other than their 'owning' thread -
that on which they are created. So here the myFrm is created on the
thread that enters this procedure, but then passed to a different
thread to show itself. Thus this second thread will be accessing UI
elements it didn't create -> bad.

The fix (if there are deeper reasons why you need to do this sort of
thing) is to move the form creation from before thread-creation to
after it. That is, at the moment you are saying:

Create form
Create thread (giving it the form)
Start thread - thread goes on to show form

Instead you should say

Create thread
Start thread - thread goes on to create form, then show it.

Probably the logical place for this new routine would be a Shared
procedure in myFrm:

Public Shared Sub NewShowDialog
    Dim f As New myFrm
    f.ShowDialog
End Sub

then replace your current myFunction with

    Dim t As New Thread(AddressOf myFrm.NewShowDialog)
    t.Start

But please first consider my first question about .Show vs
..ShowDialog...

--
Larry Lard
Replies to group please
When starting a new topic, please mention which version of VB/C# you
are using
Author
17 Jul 2006 3:38 PM
Simon Verona
See my previous reply, I've had problem with the form disappearing when the
subroutine exits...  (I'm presuming the object is killed on exit?)

I understand what you are saying about the frm creation and use being on
seperate threads.  I must admit to not thinking of having a shared entry on
the form to display itself!

Regards
Simon

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011

Show quoteHide quote
"Larry Lard" <larryl***@hotmail.com> wrote in message
news:1153150234.509877.22680@m73g2000cwd.googlegroups.com...
>
> Simon Verona wrote:
>> I think I'm doing this wrong :
>>
>> I have a class with a public shared method such as follows:
>>
>>    public shared sub myFunction
>>         dim frm as new myFrm
>>         dim t as new Threading.Thread(Addressof  myFrm.myShowDialog
>>         t.start
>>    end sub
>>
>> In the frm - the myShowDialog just does a "me.showdialog".
>>
>> The idea is that this function will display a form, but then return
>> control
>> back to the calling routine immediately without waiting for the form to
>> be
>> closed.
>
> If this is what you want, why not just .Show (rather than .ShowDialog)
> the form? Anyway...
>
>>
>> It works, but I've had several reports of the form that is displayed
>> "crashing" as it is being displayed, with random errors (I've not got a
>> sample) or the whole application just disappearing (without error).
>>
>> Can anybody assist, either by confirming or otherwise that what I'm doing
>> is
>> reasonable, or perhaps letting me know a better way.
>
> I think you are falling foul of the rule whereby UI elements cannot be
> safely interacted with from threads other than their 'owning' thread -
> that on which they are created. So here the myFrm is created on the
> thread that enters this procedure, but then passed to a different
> thread to show itself. Thus this second thread will be accessing UI
> elements it didn't create -> bad.
>
> The fix (if there are deeper reasons why you need to do this sort of
> thing) is to move the form creation from before thread-creation to
> after it. That is, at the moment you are saying:
>
> Create form
> Create thread (giving it the form)
> Start thread - thread goes on to show form
>
> Instead you should say
>
> Create thread
> Start thread - thread goes on to create form, then show it.
>
> Probably the logical place for this new routine would be a Shared
> procedure in myFrm:
>
> Public Shared Sub NewShowDialog
>    Dim f As New myFrm
>    f.ShowDialog
> End Sub
>
> then replace your current myFunction with
>
>    Dim t As New Thread(AddressOf myFrm.NewShowDialog)
>    t.Start
>
> But please first consider my first question about .Show vs
> .ShowDialog...
>
> --
> Larry Lard
> Replies to group please
> When starting a new topic, please mention which version of VB/C# you
> are using
>
Author
17 Jul 2006 5:59 PM
Larry Lard
Simon Verona wrote:
> See my previous reply, I've had problem with the form disappearing when the
> subroutine exits...  (I'm presuming the object is killed on exit?)

I'd be tempted to go back and re-examine that situation, to be honest.
To paint with a *very* broad brush, multi-threading is something you
shouldn't do unless you quite obviously _must_.

>
> I understand what you are saying about the frm creation and use being on
> seperate threads.  I must admit to not thinking of having a shared entry on
> the form to display itself!

The thought process there was that the behaviour of <creating a new
myFrm and displaying it> clearly 'belongs to' the myFrm class, but not
to any particular instance of it => shared method.

--
Larry Lard
larryl***@googlemail.com
The address is real, but unread - please reply to the group
For VB and C# questions - tell us which version
Author
17 Jul 2006 3:48 PM
Simon Verona
Larry

I had a go at implementing your thought, but of course, the "real" code is
not quite as simple as the example I posted:

The real code passes a variable through to the form when constructing  ie

    dim frm as new myfrm(myvar)
    dim t as new threading.thread(addressof frm.myShowDialog)
    t.start

I can't work out how to create a shared function that I can call on another
thread AND pass a parameter!

Regards
Simon

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011

Show quoteHide quote
"Larry Lard" <larryl***@hotmail.com> wrote in message
news:1153150234.509877.22680@m73g2000cwd.googlegroups.com...
>
> Simon Verona wrote:
>> I think I'm doing this wrong :
>>
>> I have a class with a public shared method such as follows:
>>
>>    public shared sub myFunction
>>         dim frm as new myFrm
>>         dim t as new Threading.Thread(Addressof  myFrm.myShowDialog
>>         t.start
>>    end sub
>>
>> In the frm - the myShowDialog just does a "me.showdialog".
>>
>> The idea is that this function will display a form, but then return
>> control
>> back to the calling routine immediately without waiting for the form to
>> be
>> closed.
>
> If this is what you want, why not just .Show (rather than .ShowDialog)
> the form? Anyway...
>
>>
>> It works, but I've had several reports of the form that is displayed
>> "crashing" as it is being displayed, with random errors (I've not got a
>> sample) or the whole application just disappearing (without error).
>>
>> Can anybody assist, either by confirming or otherwise that what I'm doing
>> is
>> reasonable, or perhaps letting me know a better way.
>
> I think you are falling foul of the rule whereby UI elements cannot be
> safely interacted with from threads other than their 'owning' thread -
> that on which they are created. So here the myFrm is created on the
> thread that enters this procedure, but then passed to a different
> thread to show itself. Thus this second thread will be accessing UI
> elements it didn't create -> bad.
>
> The fix (if there are deeper reasons why you need to do this sort of
> thing) is to move the form creation from before thread-creation to
> after it. That is, at the moment you are saying:
>
> Create form
> Create thread (giving it the form)
> Start thread - thread goes on to show form
>
> Instead you should say
>
> Create thread
> Start thread - thread goes on to create form, then show it.
>
> Probably the logical place for this new routine would be a Shared
> procedure in myFrm:
>
> Public Shared Sub NewShowDialog
>    Dim f As New myFrm
>    f.ShowDialog
> End Sub
>
> then replace your current myFunction with
>
>    Dim t As New Thread(AddressOf myFrm.NewShowDialog)
>    t.Start
>
> But please first consider my first question about .Show vs
> .ShowDialog...
>
> --
> Larry Lard
> Replies to group please
> When starting a new topic, please mention which version of VB/C# you
> are using
>
Author
17 Jul 2006 3:56 PM
iwdu15
look at my code example above
--
-iwdu15
Author
17 Jul 2006 4:12 PM
Simon Verona
Thanks for the example...

However, I'm not 100% positive how I would modify your example to pass a
variable to the form.

I presume that I can't set a local private variable (declared outside of ay
subroutines) and then access it from within the CreateNewFormThreadBegin
sub?   I'm presuming that can I can't directly pass any variables directly
through to the CreateNewFromThreadBegin (ie modifying it to Private Sub
CreateNewFromThreadBegin(myvar as string) )

Apologies if I've missed the obvious - Can I use the facts that it's 5pm and
very hot to mitigate my stupidity? <G>

Thanks
Simon

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011

Show quoteHide quote
"iwdu15" <jmmgoalsteratyahoodotcom> wrote in message
news:D6016E94-C059-4376-9AD8-A664332939EB@microsoft.com...
> look at my code example above
> --
> -iwdu15
Author
17 Jul 2006 4:30 PM
iwdu15
i appologize, i forgot to add the code to create a thread..silly me, heres
the updated code, im working on pass variables now...i forgot how to do it
myself


Private Delegate Sub delNewThreadBegin()


Private Sub NewThreadBeginSub()

        Dim frm As New Form1

        frm.ShowDialog()

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

        Dim thr As New Threading.Thread(AddressOf ThreadStart)

        thr.Start()

    End Sub

    Private Sub ThreadStart()

        Dim x As New delNewThreadBegin(AddressOf NewThreadBeginSub)

        Me.Invoke(x)

    End Sub

--
-iwdu15
Author
17 Jul 2006 4:51 PM
iwdu15
i cant figure it out rite now, im a 17 year old at work trying to multi task
and its nto working too well so my code doesnt even make sense to me....il
write the answer when i get home, i have a few examples on my home computer
--
-iwdu15
Author
17 Jul 2006 10:36 PM
Tom Shelton
Simon Verona wrote:
Show quoteHide quote
> I think I'm doing this wrong :
>
> I have a class with a public shared method such as follows:
>
>    public shared sub myFunction
>         dim frm as new myFrm
>         dim t as new Threading.Thread(Addressof  myFrm.myShowDialog
>         t.start
>    end sub
>
> In the frm - the myShowDialog just does a "me.showdialog".
>
> The idea is that this function will display a form, but then return control
> back to the calling routine immediately without waiting for the form to be
> closed.
>
> It works, but I've had several reports of the form that is displayed
> "crashing" as it is being displayed, with random errors (I've not got a
> sample) or the whole application just disappearing (without error).
>
> Can anybody assist, either by confirming or otherwise that what I'm doing is
> reasonable, or perhaps letting me know a better way.

Simon...

All of this really depends on your architecture.  Is this routine that
is showing the form on a background thread?  If it is, that would
explain why the form exits when the routine ends.  If it is on a
background thread, there is no message pump and the form will exit when
the routine ends because the thread exits.

Here is three different methods of showing a form:

Option Strict On
Option Explicit On

Imports System
Imports System.Threading
Imports System.Runtime.InteropServices


Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form
Designer
    'It can be modified using the Windows Form Designer.
    'Do not modify it using the code editor.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents Button3 As System.Windows.Forms.Button
    <System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.Button2 = New System.Windows.Forms.Button
        Me.Button3 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(0, 0)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(328, 23)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Show Form On Current Thread (Form.Show)"
        '
        'Button2
        '
        Me.Button2.Location = New System.Drawing.Point(0, 28)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(328, 23)
        Me.Button2.TabIndex = 1
        Me.Button2.Text = "Show Form On New Thread (Application.Run)"
        '
        'Button3
        '
        Me.Button3.Location = New System.Drawing.Point(0, 56)
        Me.Button3.Name = "Button3"
        Me.Button3.Size = New System.Drawing.Size(328, 23)
        Me.Button3.TabIndex = 2
        Me.Button3.Text = "Show Form On New Thread (ShowDialog)"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(328, 82)
        Me.Controls.Add(Me.Button3)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    <DllImport("kernel32")> _
    Public Shared Function GetCurrentThreadId() As IntPtr

    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
        Dim frm As New Form2
        frm.Show()
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
        Dim thrd As New Thread(AddressOf ShowFormAppRun)
        thrd.ApartmentState = ApartmentState.STA
        thrd.Start()
    End Sub

    Private Sub ShowFormAppRun()
        Dim frm As New Form2
        Application.Run(frm)
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button3.Click

        Dim thrd As New Thread(AddressOf ShowFormDialog)
        thrd.ApartmentState = ApartmentState.STA
        thrd.Start()

    End Sub

    Private Sub ShowFormDialog()
        Dim frm As New Form2
        frm.ShowDialog()
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        Me.Text = String.Format("Main Form - Thread ID {0}",
Form1.GetCurrentThreadId())
    End Sub
End Class

Public Class Form2
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form
Designer
    'It can be modified using the Windows Form Designer.
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 30)
        Me.Name = "Form2"
        Me.Text = "Form2"

    End Sub

#End Region

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
        Me.Text = String.Format("Child Form - Thread ID {0}",
Form1.GetCurrentThreadId())
    End Sub
End Class


There are two forms here, so look out if you copy paste the code.  If
you don't find this stuff usefull, maybe you can post some code that
demonstrates more of your problem...

--
Tom Shelton [MVP]
Author
18 Jul 2006 1:29 AM
Branco Medeiros
Simon Verona wrote:
<snip>
Show quoteHide quote
> I have a class with a public shared method such as follows:
>
>    public shared sub myFunction
>         dim frm as new myFrm
>         dim t as new Threading.Thread(Addressof  myFrm.myShowDialog
>         t.start
>    end sub
>
> In the frm - the myShowDialog just does a "me.showdialog".
>
> The idea is that this function will display a form, but then return control
> back to the calling routine immediately without waiting for the form to be
> closed.
>
> It works, but I've had several reports of the form that is displayed
> "crashing" as it is being displayed, with random errors (I've not got a
> sample) or the whole application just disappearing (without error).
<snip>

It's an error to access the method of a class derived from Control
(which is the case of Form) from a thread other than the one where the
object was created. You must use the object's InvokeRequired method to
check if you're being called from another thread and if so
(InvokeRequired returned True), use Invoke to call the desired method.
The 'pattern' is somewhat like this:

  'in myForm
  'Must have the same signature of MyShowDialog
  Delegate Sub MyShowDialogCallback(Param as Integer)
  '...
  Sub MyShowDialog(Param As Integer)
    Static This As MyShowDialogCallback = AddressOf MyShowDialog
    If InvokeRequired Then
      BeginInvoke(This, New Object() {Param} )
    Else
      'Do your thing
      'blah, blah, blah
      ShowDialog
    End If
  End Sub

HTH.

Regards,

Branco.