await/async等の別スレッドからコントロールのプロパティを変更する

2021-04-10

await/async等の別スレッドからコントロールのプロパティを変更しようとすると、
コントロールの描画を行っているスレッドと異なる為、エラーとなる。

InvokeRequired で異なるスレッドからの呼び出しかを判定し、
異なる場合は Invoke で再呼び出しをすることで解決する。

public Form1()
{
    InitializeComponent();

    button1.Text = "Ready";
}

private async void button1_Click(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        SetButtonText("OK");
    });
}

protected delegate void DelegateSetButtonText(string _Text);

private void SetButtonText(string _Text)
{
    if (this.InvokeRequired == true)
    {
        DelegateSetButtonText objDelegate = new DelegateSetButtonText(SetButtonText);
        this.Invoke(objDelegate, new object[] { _Text });
    }
    else
    {
        button1.Text = _Text;
    }
}

また下記のように記載することで、メソッドを分けることなく、
明示的にメインスレッドで処理を行うこともできる。

public Form1()
{
    InitializeComponent();

    button1.Text = "Ready";
}

private async void button1_Click(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        Invoke((MethodInvoker)(() =>
        {
            button1.Text = "OK";
        }));
    });
}
Private Async Function Update_InstructionPartLabel() As Task

	Await Task.Run(
		Sub()

			Me.Invoke(New MethodInvoker(Sub()
				button1.Text = "OK"
			End Sub))

		End Sub
	)

End Function

WPFのVMでは上記Invokeが使用できない為、下記のようになる

System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => {
    // 同期処理
}));