views:

580

answers:

4

Hi,

I know this question has been asked before, but I feel it wasn't asked correctly.

I have an intensive operation and I'd like the UI to remain responsive. I've read a few posts that say Background worker is the best way to go, however, I think this assumes you have the source code to the intensive task.

I have a library that I have no source code for, the only way I can check on the progress is to attach to events that get fired and get information that way.

The example I saw on the MSDN site assumed one would have the source.

I know how to get progress (which is a percentage value) by attaching to events, but how do I get that value back to the UI?

+1  A: 

Attach to the progress events in the third party component and call ReportProgress on the BackgroundWorker. Have your UI attach to the BackgroundWorker.ProgressChanged event to update the UI.

HTH, Kent

Kent Boogaart
A: 

You can have the desired effect by using a second thread and a thread safe queue.

You can create a second thread that will listen for the events. When a new event happens it pushes the event information to a queue (thread safe- synchronized).

Using a Timer (Windows.Forms.Timer) that will check that queue every x time and in case new events exist can update the UI.

Because the timer runs in the main thread it can safely update the UI and if you make it light weight it will not block it long enough to be noticed.

Dror Helper
@Vince - perhaps but its the only way to throw events at the main thread if you do not have access to a "Control" class and don't want to create a dummy one just to throw events
Dror Helper
A: 

A similar discussion is on this Q. If you can't or don't want to use the BackgroundWorker for whatever reason you can use your own thread and marshal events from it back onto your UI thread.

private void Initialise() {      
    MyLibClass myLibClass = new MyLibClass();
    myLibClass.SomeEvent += SomeEventHandler;
    ThreadPool.QueueUserWorkItem(myLibClass.StartLongTask);
}


private void SomeEventHandler(EventArgs e) {     
   if (this.Dispatcher.Thread != Thread.CurrentThread) { 
      this.Dispatcher.Invoke(delegate { DoStuffOnUIThread(e); });
   }
   else {        
       DoStuffOnUIThread(e);     
   }
}
sipwiz
+2  A: 

The following answer is based on my gut feeling and have not actually done it a test with third party libs.

  • Call your third party lib code as usual you call in a simple background (not BackGroundWorker) thread.
  • Attach the library components' events to normal event handlers in your code (meant to update UI).
  • In the event handler code should look like this:

    private void EventHandler(object sender, DirtyEventArgs e)
    {
        if (myControl.InvokeRequired)
            myControl.Invoke(new MethodInvoker(MethodToUpdateUI), e);
        else
            MethodToUpdateUI(e);
    }
    
    
    private void MethodToUpdateUI(object obj) 
    {
        // Update UI
    }
    
nils_gate
With the Invoke method, can I just pass in the method name or do I need to create a delegate first?
Vince
Check the changes. You can use MethodInvoker delegate. Only method name will not suffice.
nils_gate