Shortest way to write a thread-safe access method to a windows forms control

后端 未结 5 1006
北海茫月
北海茫月 2020-12-02 11:47

In this article:

http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx

The author uses the following method to make thread-safe calls to a Windows For

相关标签:
5条回答
  • 2020-12-02 11:58

    This may be obvious to most, but you can take the accepted answer and add another method if you need to retrieve the value...

    public static T SynchronizedFunc<T>(this ISynchronizeInvoke sync, Func<T> func)
    {
        if (!sync.InvokeRequired)
        {
            // Execute the function
            return func();
        }
    
        // Marshal onto the context
        return (T) sync.Invoke(func, new object[] { });
    }
    

    I used this recently to get handle of the form in a thread-safe way...

    var handle = f.SynchronizedFunc(() => f.Handle);
    
    0 讨论(0)
  • 2020-12-02 12:14

    The shortest solution I have found is shown in the button example below where the goal is to change the text of a button.

        if (buttonX.InvokeRequired)
            buttonX.Invoke((Action)(() => buttonX.Text = "Record"));
        else
            buttonX.Text = "Record";
    
    0 讨论(0)
  • 2020-12-02 12:17

    Edit: I should mention I would not consider this to be a Best Practice

    If you are using 3.5 you can make an extension method to the effect of:

    public static void SafeInvoke(this Control control, Action handler) {
        if (control.InvokeRequired) {
            control.Invoke(handler);
        }
        else {
            handler();
        }
    }
    

    this is basically taken from: Here

    Then use it like:

    textBox1.SafeInvoke(() => .... );
    

    Of course modify the extension etc for your usages.

    0 讨论(0)
  • 2020-12-02 12:20

    C# 3.0 and after:

    An extension method would generally be the way to go, since you're always going to want to perform an action on an ISynchronizeInvoke interface implementation, it's a good design choice.

    You can also take advantage of anonymous methods (closures) to account for the fact that you don't know what parameters to pass to the extension method; the closure will capture the state of everything needed.

    // Extension method.
    static void SynchronizedInvoke(this ISynchronizeInvoke sync, Action action)
    {
        // If the invoke is not required, then invoke here and get out.
        if (!sync.InvokeRequired)
        {
            // Execute action.
            action();
    
            // Get out.
            return;
        }
    
        // Marshal to the required context.
        sync.Invoke(action, new object[] { });
    }
    

    You'd then call it like this:

    private void SetText(string text)
    {
        textBox1.SynchronizedInvoke(() => textBox1.Text = text);
    }
    

    Here, the closure is over the text parameter, that state is captured and passed as part of the Action delegate passed to the extension method.

    Before C# 3.0:

    You don't have the luxury of lambda expressions, but you can still generalize the code. It's pretty much the same, but not an extension method:

    static void SynchronizedInvoke(ISynchronizeInvoke sync, Action action)
    {
        // If the invoke is not required, then invoke here and get out.
        if (!sync.InvokeRequired)
        {
            // Execute action.
            action();
    
            // Get out.
            return;
        }
    
        // Marshal to the required context.
        sync.Invoke(action, new object[] { });
    }
    

    And then you call it with anonymous method syntax:

    private void SetText(string text)
    {
        SynchronizedInvoke(textBox1, delegate() { textBox1.Text = text; });
    }
    
    0 讨论(0)
  • 2020-12-02 12:20

    1) Using anonymous delegate

    private void SetText(string text)
    {
        if (this.InvokeRequired)
        {    
            Invoke(new MethodInvoker(delegate() {
                SetText(text);
            }));
        }
        else
        {
            this.textBox1.Text = text;
        }
    }
    

    2) AOP approach

    [RunInUIThread]
    private void SetText(string text)
    {
        this.textBox1.Text = text;
    }
    

    http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2

    3) Using lambda expressions (outlined by others).

    0 讨论(0)
提交回复
热议问题