简体   繁体   中英

What is considered good programming practice in multi-threaded winform applications with delegate usage?

I'm modifying an application written in C# that makes heavy-use of multi-threading to play audio files and display images to a user. Given that it is multi-threaded, I need to use the Invoke method often to change form elements. I'm running into a pattern that I'm not very comfortable with, where I find myself writing frequent, small, delegate methods that typically only do one thing. An example of this is as follows:

delegate void setImageCallback(Image img);
private void setImage(Image img)
{
    this.pictureBox1.Image = img;
}

private void someOtherMethod()
{
    ...
    if (this.pictureBox1.InvokeRequired)
    {
        this.Invoke(new setImageCallback(setImage), Image.FromFile("example.png");
    }
    else
    {
        this.pictureBox1.Image = Image.FromFile("example.png");
    }
    ...
}

How do people generally handle these situations, so that you don't find yourself writing an absurd number of delegates and methods just to remain thread-safe? Obviously, consolidation of similar methods is great, but if I potentially need to update every form element on my form, I don't want to have a "modify" delegate and method for each of these.

Thanks.

A good example is here .

this.BeginInvoke( (Action) (()=>
    {
        pictureBox1.Image = Image.FromFile("example.png");
    }));

You definitely don't need a separate delegate for each. You can use Action delegates and lambda expressions to simplify it, like this:

private void SomeOtherMethod()
{
    Action action = () => pictureBox1.Image = Image.FromFile("example.png");
    if (pictureBox1.InvokeRequired)
    {
        Invoke(action);
    }
    else
    {
        action();
    }
}

Or you can separate out the if statement and InvokeRequired check and generalize it even more, like this:

public static void InvokeIfRequired(Control control, Action action)
{
    if (control.InvokeRequired)
    {
        control.Invoke(action);
    }
    else
    {
        action();
    }
}

private void SomeOtherMethod()
{
    InvokeIfRequired(() => pictureBox1.Image = Image.FromFile("example.png");
}

I would use the MethodInvoker type in conjunction with an anonymous method or lambda expression. I would also build the invocation logic into the method itself, rather than using a separate thread-safe method:

void SomeMethod(/* with whatever args */) {
    if (InvokeRequired)
        Invoke(new MethodInvoker(() => SomeMethod(/* args used to call method */)));
    else
        // the method body itself
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM