views:

251

answers:

3

In a Windows Forms application I want to separate the GUI from the logic. The user requests are complex and involve communications so I don't want it to depend on the GUI thread. The structure should be something like:

        GUI -----> splash screen ---------> User Form --------------> ...
              |                        #
              | create Manager thread  | Show this Form
              #                        |
    Manager -----> Check user type -------> Wait for user command --> ...

Which are your advices, guidelines or patterns for a design like this one? Is it the correct choice? Thank you!

EDIT The Manager thread should control the GUI and not in reverse. Moreover, the Manager thread should live during all the application time.

+3  A: 

Traditionally work like this is done using a BackgroundWorker

Basically it is a simple class that gives you the ability to perform a function on a worker thread and then will automatically invoke back to the UI thread after that function is complete. During the time that the function is being run the UI is unblocked and can display a progress message, or process other user input (cancel for example).

The result is similar to your pattern, but a separate thread is created and destroyed (well, there is pooling really...) for each task.

UI thread ---> Show splashscreen------------------->Show window-------
                      |                           |return to UI      |
                      | create background worker  |                  |
                      -> Process user ------------                   ->Perform query etc.


Okay, based on your comment:

You can use a pattern like that, it is a simple case of eventing. Give the UI access to your manager so that it can perform a method call on it and register for events when the task is completed (this link shows the two major patterns for async operations in .NET). Inside the manager you'll need to maintain a list of tasks that can be performed in sequence on the single thread and ensure that the events that are called to return the results to the UI are properly invoked so that are run on the main UI thread (basically recreate the background worker pattern).

I'm not sure what you are hoping to gain by doing this, is there a reason the application needs to be limited to two threads? Are you concerned about the cost of creating backgroundworkers? Do you need some kind of query queue system? The examples in the diagram in your question don't seem to require the complexity of this kind of pattern.

Martin Harris
But I want the manager to be the thread that handles all the logic, not just one operation.
yeyeyerman
The problem with this application is that each user request must execute a process to talk to a FPGA, with some real time delays and that kind of stuff.
yeyeyerman
The purpose of background workers are to deal with situations where there is latency between a task being requested by the user interface and the result being returned. I'm not sure why you seem to think that everything must be done on the same thread and you can't use the task synchronisation provided by the framework's BackgroundWorker class.
Martin Harris
Thanks Martin, I guess I should explore the BackgroundWorker pattern in more deatil.Anyway, I don't know how can be mainting only two threads more complicated that generating a BackgroundWorker for every task.
yeyeyerman
The only thing is that conceptually I would like to give the Manager more weight than the GUI. But I'm considering your advice with the BackgroundWorker, because it seems to be really time saving.
yeyeyerman
Maintaining two threads in more complicated because with the BackgroundWorkers you aren't really maintaining any threads, it is all done for you. Basically it is the difference between saying to someone "I need this done, go and do it and send me an email when you're done" or saying "I need this done, but we only have one desk and Bob's using it right now so you'll have to wait. And when you do finish, send me an email - but I can't guarantee the quality of the servers since I sent them up myself this morning"
Martin Harris
+2  A: 

You should use a background worker to complete your task.

It has events that will be very handy. DoWork and RunWorkerCompleted, which will come in very handy.

You can also try using Threads, They will look something like this: (Bear in mind, when you use Threads, if you want to do any work with the UI Thread, you must Invoke(), otherwise you will received a CrossThreadException)

private delegate void MyFunctionCaller();

//This will set up your worker thread and set it off
private void SetThreadToDoWork()
  {
  ThreadStart threadStart = new ThreadStart(DoWork);
  Thread MyThread = new Thread(threadStart);
  MyThread.Start();

  ShowSplashScreen();
  }

private void DoWork() 
  {
  DoMyWork();
  WorkCompleted();
  }

private void WorkCompleted()
{
if (InvokeRequired == true)
  {
  MyFunctionCaller InvokeCall = delegate { WorkCompleted(); };
  Invoke(InvokeCall);
  }
else
  {
  //Back to the UI thread now.
  }
}

OPs Edit

You can create the thread wherever you like, once it has started you can have it completing several functions. But keep in mind that you need to Invoke() if you want to complete any work that the UI Thread can only complete otherwise you will get a CrossThreadException.

ThePower
Thanks for the crossthreading stuff.
yeyeyerman
No worries, best things to look up are Invoke(), BeginInvoke() and InvokeRequired.
ThePower
+1  A: 

I've developed a similar project. GUI launch the manager on a different Thread. Manager have some method to get commands from the GUI. GUI is listening to Manager's events, so it's updated only when Manager raise up an event. To avoid crossthreading, i used to "Invoke" methods

michele
I'm agree with the GUI listening to Manager's events. Could you give me more information about the avoid crossthreading part?
yeyeyerman
I'm using mostly Invoke() to update informations in the GUI, simply but perfect for my requirements.
michele