views:

82

answers:

5

I have an application wherein I would like a function to be executed in the same thread when an event is fired. For example:

SomeCode()
{
   // Do something...

   // Fire event to run SomeOtherCode().
}

SomeOtherCode()
{
   // Do something else...
}

I do not want to simply call the function because it will hold things up. SomeOtherFuction() needs to be executed in the same thread because it needs to access the form controls, and I need it to begin execution from an event trigger firing. I am using Microsoft Visual C# 2008 Express Edition. Thanks.

::: EDIT::: Additional Details: The bottom line is that the contrustor of my form application is taking far too long to complete, and it is causing a significant delay, from when the user launches the application to when the application window appears on the display. This is not a problem on faster computers, but on slower computers it is a big problem. I need to exit the contrustor as soon as possible, thus allowing the framework to draw the application window, and continue initialization outside the constructor. (All essential items would still be initialized inside the constructor.)

An event-triggered function call would be ideal. I would prefer not to use a timer. Interlacing the affected code with Invokes is impractical in my situation and would require much more time to implement than I have to work on this. A simple example of an event-driven function call is all I'm really looking for. Thanks.

A: 

You seem to be asking to run SomeOtherCode() later.

You can call BeginInvoke (either from the UI thread or from any other thread) to queue a function to run during the next message loop:

BeginInvoke(new Action(SomeOtherCode));
SLaks
A: 

It seems that you would want to add an event to the class that exposes the SomeCode method. Then, the class that implements the SomeOtherCode method would attach an event handler that calls the SomeOtherCode method.

It's completely viable to have this done in one class, in case you have some sort of state model where you want to add/remove the call depending on some other logic.

casperOne
A: 

I think you want to put SomeOtherCode into a Task or BackgroundWorker, which would then synchronize with the UI thread to send it updates.

I recently posted on my blog a class that makes updating the UI from a Task as easy as from a BGW. I do recommend using Task rather than BackgroundWorker.

Stephen Cleary
A: 

Simialr to what Stephen said, I would recommend that you move as much of that initialization code to a background thread or task. Let the background thread do as much work as possible, then send the necessary window updates to your UI thread via Action<>'s. Here's some quick psuedo-sample code:

protected void LoadMyListInBackground(object state)
{
   List<string> myList = Databse.FetchMyList(myParameters); // This take a while, so the UI thread isn't waiting

   ShowMyList(myList);
}

protected void ShowMyList(List<string> theList)
{
  if(InvokeRequired)
    Invoke(new Action<List<string>>(ShowMyList, theList);
  else
  {
    foreach(string item in theList)
      myListBox.Items.Add(item);
  }
}

In this example the UI thread is free to keep drawing your window while the background thread does the lengthy database work. The problem is, even if you fire an event outside of your constructor, and that event occurs on the UI thread and takes a long time, the user might see the window but that window is going to 'freeze' and possibly appear to be 'crashed' to the user. This technique prevents that and provides a better user experience.

Coding Gorilla
+1  A: 

From your posts it's seems like you're confusing a few issues. The standard pattern in .Net is for events to run synchronously. The following lines are essentially identical in terms of when they execute.

Option #1

SomeCode();
SomeOtherCode();

Option #2

SomeEvent += delegate { SomeOtherCode(); }
...
SomeCode();
SomeEvent(this,EventArgs.Empty);

If you want to unblock the UI thread and run the code later you'll need to use some mechanism to delay the running of the SomeOtherCode function. The easiest way to do this in a WinForms application is to use a WinForms Timer instance. This will raise an event on the UI thread at a later point in time that you can respond to. It also won't block the UI thread during this time allowing your form to continue processing.

JaredPar
But once the event fires and the SomeOtherCode function runs (on the UI thread) the user interface will be blocked until SomeOtherCode returns. To the user it may appear that the app has suddenly and mysteriously hung.
ShellShock
@ShellShock, that's true for any function that runs on the UI thread which takes an inordinate amount of time to run.
JaredPar
I ended up going with the Timer solution. Mainly, it's quick and simple, which is what I needed. I gave it a 1 second timeout, which should be more than enough time on even the slowest of machines. Thanks!
Jim Fell