當使用子執行緒(Other Thread)更新主執行緒所顯示的UI元件時,通常會遇到「跨執行緒作業無效: 存取控制項 ... 時所使用的執行緒與建立控制項的執行緒不同」這個錯誤,可以利用UI.InvokeRequired來進行判斷跨執行緒的問題與導正回主執行緒。

 

當函數是沒有參數時,可以不用自建委派,直接利用C#提供的MethodInvoker即可:

private void NoneParameterFunction()
{
    if (UI.InvokeRequired)
    {
        MethodInvoker TA = new MethodInvoker(NoneParameterFunction);
        this.Invoke(TA, new object[]{});
    }
    else
    {
        // Do something...
    }
}

當函數是有參數時,需要自建委派,利用該委派來回呼方法,以達到導正執行緒的目的:

1. 先建立委派

private void delegate WithParameterFunctionHandler(string sParam);

2. 在方法中使用委派

private void WithParameterFunction(string sParam)
{
    if (UI.InvokeRequired)
    {
        WithParameterFunctionHandler TA = new WithParameterFunctionHandler(WithParameterFunction);
        this.Invoke(TA, new object[] {sParam});
    }
    else
    {
        // Do something...
    }
}

 

另可以參考Shin.Li的文章,將InvokeRequired寫成static class方便使用,也是一個亮點用法。

未免參考網頁消失,節錄內容如下,原文詳見:https://dotblogs.com.tw/shinli/2015/04/16/151076

 

為了更有效便利的使用Invoke跟InvokeRequired去執行跨執行緒控制項操作,我通常會把這個方法撰寫class的擴充方法,並且加入MethodInvoker 委派/lambda的應用。

public class main
{
    //參考用controls
    TextBox tb = new TextBox();

    void Func()
    {
        //使用lambda
        tb.InvokeIfRequired(() =>
        {
            tb.Text = "hello";
        });

        //使用Action
        tb.InvokeIfRequired(helloAction);
    }

    void helloAction()
    {
        tb.Text = "hello";
    }
}

//擴充方法
public static class Extension
{
    //非同步委派更新UI
    public static void InvokeIfRequired(this Control control, MethodInvoker action)
    {
        if (control.InvokeRequired)//在非當前執行緒內 使用委派
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }
}
創作者介紹
創作者 幽嵐飋翼 的頭像
wings890109

幽嵐飋翼

wings890109 發表在 痞客邦 留言(0) 人氣( 6649 )