Marisha
Marisha

Reputation: 196

Retrieving Windows Form properties during multithreading

I am somewhat familiar with VB.NET but am very new to multi-threading.

I have a situation in which I have started a new thread separate from the main process, and with that new thread I have created and displayed a new form. One of the methods in the new form's Load() procedure is to set the form's location, dependent on the main form (Form1's) location.

I am finding, however, that when I refer to Form1's properties from this thread, they are not being accurately retrieved. In particular, the Location.X and Location.Y properties appear as 0, when they are in actuality more substantial integers.

Private Sub SetLocation()

    Dim parentx, parenty, parentw, parenth As Integer
    Dim parentForm As Form = My.Forms.Form1

    parentx = parentForm.Location.X
    parenty = parentForm.Location.Y

    parentw = parentForm.Width
    parenth = parentForm.Height

    Me.Location = New Point(parentx + (parentw / 2), parenty + (parenth / 2))

End Sub

The part I find the strangest about this is that when I set a breakpoint within this SetLocation() method, and the program breaks for debugging, the X and Y variables will first register as 0 in the value display:

x and y zero values

But then, while I'm debugging, if I access the information about Form1 in the IDE in its paused state, without resuming the application, and then return to viewing the X and Y values, the properties will eventually display as their actual values.

x and y actual values

Is it normal for form properties to be loaded in the midst of a debugging break point? Is this phenomenon a known aspect of multithreading in VB.NET? And will I have to go through much more complicated thread-communication methods in order for my new thread to access this information?

Thank you!

Upvotes: 1

Views: 79

Answers (1)

Trevor_G
Trevor_G

Reputation: 1331

This is hard to explain but I will do my best.

In your usage Form1 is the Form Class type, NOT the form itself.

This is a common and ongoing confusion in VB.NET.

  My.Forms

Lists only the form designs you have defined in the project... NOT THE ACTIVE FORMS THEMSELF.

If your project starts with Form1, VB.NET creates an INSTANCE of that form which has it's own identity and memory allocation.

When you open a new form that references the initial form, you need to pass that identity to the second form by reference.

The best way to do that, IMHO is to augment Form2's constructor. As Follows.

Public Sub New(owner_Form As Form1)
    Owner = owner_Form
    ' This call is required by the designer.
    InitializeComponent()

End Sub

Then in your SetLocation code use the following

    parentx = Owner.Location.X
    parenty = Owner.Location.Y
    parentw = Owner.Width
    parenth = Owner.Height

NOW: your example code does not indicate where the thread is that starts the new form.

If the thread code is part of the Form1 Class you can simply do the following in your thread code.

Dim Form2 as New Form2(me)

If it is deeper than that, you would need to pass the Me down through the hierarchy.

If your application is not overly complicated, an Alternative Method is to use some other Global or shared Class Reference to identify the main form.

Example:

In a Global Module add

Public Main_Form as Form1

And in Form1_Load add

Main_Form = Me

Then in your SetLocation code use the following

    parentx = Main_Form.Location.X
    parenty = Main_Form.Location.Y
    parentw = Main_Form.Width
    parenth = Main_Form.Height

WHY IS IT SO COMPLICATED

What you have to force yourself to remember is that during execution your program can create any number of Form1s, or any other form for that matter. Each one has it's own identity.

My.Forms only lists the prototype.

CROSS-THREADED UI REFERENCING

As Enigmativity mentions, referencing the UI from a non UI-Thread can be a dangerous place to go and is fraught with issues that will drive you batty. I do agree usage of the UI through another thread is treading on very thin ice, however there are occasions, if the model is fully understood, that such referencing is acceptable. Read-Only usage like the current example being a case in point.

However, this "answer" would be the same whether the second form was started from a new thread or simply spawned as a normal Form.Show() from the initial form

PS: You could also simplify our code

Me.Location = <whatever method you choose>.Location
Me.Size = <whatever method you choose>.Size

Upvotes: 3

Related Questions