0

ive searched high and low for invoke required related posts on stack overflow.. its helped me learn a lot.. but i have a couple of questions.. not only relating to invoke required but also background worker.. bear with me please.. :)

my application does something long and needs to update the gui in the process (progress bar, status bar, text boxes).. i used a thread but it gave the dreaded cross-thread exception when updating the UI.. i recently (kinda) got the hang of using invokerequired properly..[Automating the InvokeRequired code pattern].. the code ive used from this post is:

public static partial class CHelper
{
    public static void InvokeIfRequired(this Control oCtrl, MethodInvoker fnAction)
    {
        if (oCtrl.InvokeRequired)
        {
            oCtrl.Invoke(fnAction);
        }
        else
        {
            fnAction();
        }
    }
}

public partial class Form1 : Form
{
    public void Test()
    {
        this.InvokeIfRequired(() =>
        {
            Text = "Window Title";
            button1.Text = "Hello";
        });
        button1.InvokeIfRequired(() =>
        {
            Text = "Window Title";
            button1.Text = "Hello";
        });
    }
}

now here's something i noticed.. this.InvokeIfRequired and button1.InvokeIfRequired both do the same thing.. why is this so? i was expecting that the Text in button1.InvokeIfRequired would correspond to button1's text property.. but instead it refers to the parent form's.. to me this seems silly, unintuitive, and wrong.. or maybe im doing something wrong..


another question.. i didnt get the hang of invokerequired back then so i resorted to using background worker.. and using progress event to update the gui..

public partial class Form1 : Form
{
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        backgroundWorker1.ReportProgress(0, "Hello World");
    }
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (e.UserState != null)
        {
            button1.Text = e.UserState as string;
        }
    }
}

so far, it hasnt caused me problems.. i wanna know which of these two approaches is better? and why? also, is there a way to pass data to the prevous InvokeIfRequired function?

thanks.. =)


edit 01: Is there any difference between using Invoke for the parent form or for the target control?.. yes form.invoke and control.invoke is the same.. but why should it be? its not intuitive, and gives the wrong impression..

Community
  • 1
  • 1
AweSIM
  • 1,651
  • 4
  • 18
  • 37

1 Answers1

0

Well, it doesn't matter at all for a Button control. Windows has a hard rule that all the child windows of a window must be owned by the same thread. So by that rule, both the form's and the button's Begin/Invoke() methods will marshal the call to the correct thread.

Do note that it gets to be awkward when you need to update a property of a component that doesn't have a Handle property. Like a ToolStripButton. Now you have to pick another control. So favor consistency and always use the form.

And sure, do favor BackgroundWorker. It has a knack for helping you to get this right by limiting the number of ways you can shoot your foot.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • lol for "limiting the number of ways you can shoot your foot".. =D.. wish i could upvote it if i had sufficient rep.. =).. your response makes sense.. – AweSIM Nov 04 '12 at 08:52
  • i had a followup question with invokeofrequired but i guess ill mark this correct (since it is) and start a new thread instead (to keep things tidy here) =).. thanks.. – AweSIM Nov 04 '12 at 09:11