none
How can I use the delegate to update the user interface from a thread?

    Question

  • hi:)

    I make a thread to do some work, here I want to see how the thread is going on. How can I use the thread to update the label text(used to display the message from the thread).

    I am a newer in c# , any advance will be helpfull!

    thanks in advace.

    Saturday, March 25, 2006 4:29 AM

Answers

  • Your class should have an event that must be raised when *something* happens in your worker-thread.   For instance, your class can have an event that is raised when you want to show progress of your thread.

    class TheJob
    {
         public event EventHandler ShowProgress;

         public void Run()
         {
               Thread t = new Thread (new ThreadStart(DoWork));
               t.Run();
         }

         private void DoWork()
         {
              // Do your work on the other thread here and
              // raise an event to show the progress
             OnShowProgress
         }

    }

    The OnShowProgress method looks like this:
    private void OnShowProgress()
    {
          if( ShowProgress != null )
         {
                ISynchronizedInvoke s = ShowProgress.Target as ISynchronizedInvoke;

               if( s != null & s.InvokeRequiered )
               {
                     s.Invoke (ShowProgress, new object[]{this, EventArgs.Empty});
               }
               else
               {
                     ShowProgress (this, EventArgs.Empty);
               }
         }
    }

    Your UI can subscribe on the ShowProgress event:

    TheJob myJob = new TheJob();
    myJob.ShowProgress += new EventHandler (UpdateLabel);
    myJob.Run();

    And the UpdateLabel method looks like this:
    private void UpdateLabel(object sender, EventArgs e)
    {
        label1.Text = "Showprogress called";
    }


    But, why don't you use the BackGroundWorker class ?
    Sunday, March 26, 2006 7:36 AM

All replies

  • coz you are working on another thread you cannot acess directly the label.. if the label wasnt created by that thared..

     

    and howd you guess you need a delegate , and a methofd BeginInvoke

    delegate void MyDelegate(string s); // or some other paramters

    private void AMethodInYourThread(//... some paramters)

    {

           MyDelegate call=new MyDelegate(DoWork);

    // the begin Invoke takes 2 paramters, 1 is the delegates whose methods will be called

    // 2 the paramters that that methods in the delegate needs them..

           label1.BeginInvoke(call, "i am running");

    }

    void DoWork(string s)

    {

         label1.Text=s;

    }

     

    Cheers!

    Saturday, March 25, 2006 7:54 PM
  • Thank you for your help!

    But I cannt really understand you.

    If the method  'AMethodInYourThread' is writen in the thread class,how can it  use the label1,which is  created in the ui thread(another thread).

     

     

     

     

    Sunday, March 26, 2006 3:43 AM
  • Your class should have an event that must be raised when *something* happens in your worker-thread.   For instance, your class can have an event that is raised when you want to show progress of your thread.

    class TheJob
    {
         public event EventHandler ShowProgress;

         public void Run()
         {
               Thread t = new Thread (new ThreadStart(DoWork));
               t.Run();
         }

         private void DoWork()
         {
              // Do your work on the other thread here and
              // raise an event to show the progress
             OnShowProgress
         }

    }

    The OnShowProgress method looks like this:
    private void OnShowProgress()
    {
          if( ShowProgress != null )
         {
                ISynchronizedInvoke s = ShowProgress.Target as ISynchronizedInvoke;

               if( s != null & s.InvokeRequiered )
               {
                     s.Invoke (ShowProgress, new object[]{this, EventArgs.Empty});
               }
               else
               {
                     ShowProgress (this, EventArgs.Empty);
               }
         }
    }

    Your UI can subscribe on the ShowProgress event:

    TheJob myJob = new TheJob();
    myJob.ShowProgress += new EventHandler (UpdateLabel);
    myJob.Run();

    And the UpdateLabel method looks like this:
    private void UpdateLabel(object sender, EventArgs e)
    {
        label1.Text = "Showprogress called";
    }


    But, why don't you use the BackGroundWorker class ?
    Sunday, March 26, 2006 7:36 AM
  • I don't know if I would do it this way, Delegate.Target may not return the object that you want if there is more than one method in the invocation list.

    Also, you're letting the publishing class take the responsibility of invocation, rather that the subscriber, this means that the subscriber has to have some sort of foreknowledge of the actual implementation of the publisher.

    I do agree, start with the BackgroundWorker class and have it report its progress to you.

    The important thing to remember is that you can't touch the UI outside of the thread which the UI was created in, so you can create a delegate that takes a string for example to update a control...

    FormUpdateHandler hand = delegate(string text)
    {
         form.StatusLabel.Text = text;
    };

    Invoke(hand, new object[] { message });

    ...an example of an anonymous delegate you could put in the method that handles the reportspgrogress event of BackgroundWorker.

    Sunday, March 26, 2006 8:42 AM
  • Thank you for  reply!

    The problem have been resolved by taking the "delegate".

    Since you advice me to use the to use the BackgroundWorker class,

    but  I do not know more about BackgroundWorker. Here I want you can tell me more about BackgroundWorker. Some codes will be helpful.

    Thanks in advace. 

    Sunday, March 26, 2006 2:19 PM
  • If I understand your question, it's not necessary to initially use a delegate to call a UI routine from within a thread.  You can simply call the UI routine, wherever it is, and put the delegate in there.
     
    Here is the logic that I use successfully:
     
     
     
    private void UpdateUi()
    {
     
         if(InvokeRequired)
              {
               MethodInvoker Callback = new MethodInvoker(UpdateUi);
               Invoke(Callback);
               }
         else
              {
                ...all my ui update code
              }
    }
     
     
     
    MethodInvoker is a predefined delegate if you have no arguments to pass to your UI routine.  If you do have arguments, it's just a bit more work as follows:
     
     
    private delegate void UiCallback(arg1, arg2, ...);
    private void UpdateUi(arg1, arg2, ...)
    {
     
         if(InvokeRequired)
              {
               UiCallback Callback = new UiCallback(UpdateUi);
               Invoke(Callback, new object[] {arg1, arg2, ...});
               }
         else
              {
                ...all my ui update code
              }
    }
     
    Sunday, March 26, 2006 6:21 PM
  • Not really a question or answer, just wanted to say I think this is a great thread, and I found it mighty useful !

    - Jonathan

    Friday, April 07, 2006 11:51 AM