4
votes

I want to do the following (c#)

  • I have a Form,let's call Form1
  • Form1 creates Form2
  • Form2's constructor is executed (GUI,variables..). Last instructions of Form2 are: create and show Form3
  • Form2 contains Label1
  • Form2 creates Form3 and pass a reference of itself to Form3
  • Form3 edit label1(of Form2) many times (let's say 100)

This is ok..all working but.. The problem is: Form3 takes a long time to run all operations (let's 10 seconds). In the end(at the SAME time) Form2 and Form3 are both shown but I want Form2 is visible BEFORE Form3,because I want which,while Form3 operations are executed (including editing label1 on Form2),Form2 show each update of Label1 (like "Doing: operation 1",then "Doing: operation 2" and so on..).

I also tried to make a button (Button1) on Form2,defining Button1_onClick() event and fulfilling its content with "create and show Form3". But when I click Button1,Form2 "disappears"(like when a Windows application is blocked and it becomes "paused") and it show just the final label ("Operation: 100") in the same moment which appears Form3.

Summary of my question: --> I have 3 Forms

  • Form1
  • Form2 (with Label1)
  • Form3 (editing Label1 in Form2)

--> What it should happen:

  • Form1 creates and shows Form2
  • Form2 creates and shows Form3
  • Form3 make various operations (like creating a list,ordering it,..) and for each operation updates Label1 (and the user MUST see the update process) in Form2

All Form2 operations are invocated from a function called in the constructor of Form2 like: Form2_Constructor() => calling makeOperations() --> makeOperations() => calling Operation1(),then Operation2() and finally Operation3() where each OperationX() contains a cycle (let's say of 30 iterations) doing some operation and calling Form2.setLabel1("Operation Name");

My idea (as title says) is to make two different threads.. .. or at least find a way to have two forms running in "parallel mode"(this way Form2 doesn't idle when Form3 is executing operations).

Any idea how to solve this matter?

3
Please don't prefix your titles with "C#:" and such. That's what the tags are for.John Saunders

3 Answers

3
votes

If you really wanted two different forms running on separate threads then you will need to create another thread which runs a message loop via Application.Run. However, this approach is not advised. It can cause weird problems and it makes it inconvenient for the two different forms to access each other since all accesses from one to the other require marshaling using Control.Invoke.

I advise sticking with a single UI thread. Get as much of the long running code currently executed by Form3 into a worker thread. As the worker thread makes progress you can slowly publish the results to Form3. Publishing the results to Form3 can be done in one of two ways.

  • Have the worker thread push results to Form3 by calling Invoke or BeginInvoke
  • Have Form3 poll a shared data structure for results published by the worker thread

Those that monitor my answers already know which one I am going to recommend: the later method in which the UI thread polls for the results. It has the following advantages.

  • It breaks the tight coupling between the UI and worker threads that Control.Invoke imposes.
  • It puts the responsibility of updating the UI on the UI thread where it should belong anyway.
  • The UI thread gets to dictate when and how often the update should take place.
  • There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
  • The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).

If the work currently being performed by Form3 cannot be easily moved to a worker thread (perhaps it is manipulating UI controls most of the time which can only done from the UI thread hosting the form) then you will need to slow down the rate at which this work is performed to allow more time for the form to respond to user input. This means you will be forced to make some sacrifices. For example, instead of filling a grid with thousands of rows you may need to fill it with only a hundred at a time and provide some kind of paging behavior that allow the user to move to the next hundred.

0
votes

In general, you should keep all of your UI on the main thread and do long-running tasks in the background.

Depending on the version of .Net you're using and what that background work is, you might use a BackgroundWorker, the ThreadPool, or the .Net 4.0 Task classes.

Regardless of which of those you use, when you update the status in your UI, you'll have to use the control's Invoke method to update it, otherwise you'll get an exception about trying to update a control from a thread it wasn't created on.

There are a number of articles written on background threads and updating the UI.

Here is an article on the .Net 4 Task and WinForms (full disclosure, it's my article).

Here is a basic VS project mimicking what you describe -- three forms launching each other with the 3rd form performing background work and updating status on form 2 (with the background work done by a BackgroundWorker control).

-4
votes

Yeah. Sit down and program. Start another thread, in it create the other form and start the dispatcher. Then use standard message passing semantics for talks between the forms.