수색…


다른 스레드에서 양식 컨트롤에 액세스

컨트롤을 만든 GUI 스레드가 아닌 다른 스레드에서 텍스트 상자 나 레이블과 같은 컨트롤의 특성을 변경하려면 호출해야합니다. 그렇지 않으면 다음과 같은 오류 메시지가 표시 될 수 있습니다.

"크로스 스레드 작업이 유효하지 않습니다 : 컨트롤 'control_name'이 (가) 만들어진 스레드가 아닌 다른 스레드에서 액세스했습니다."

이 예제 코드를 system.windows.forms 폼에서 사용하면 해당 메시지와 함께 예외가 발생합니다.

private void button4_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(updatetextbox);
    thread.Start();
}

private void updatetextbox()
{
    textBox1.Text = "updated"; // Throws exception
}

대신 텍스트 상자의 텍스트를 소유하지 않는 스레드에서 텍스트를 변경하려면 Control.Invoke 또는 Control.BeginInvoke를 사용하십시오. 또한 Control.InvokeRequired를 사용하여 컨트롤을 호출해야하는지 확인할 수 있습니다.

private void updatetextbox()
{
    if (textBox1.InvokeRequired)
        textBox1.BeginInvoke((Action)(() => textBox1.Text = "updated"));
    else
        textBox1.Text = "updated";
}

이 작업을 자주 수행해야하는 경우 호출 가능 객체에 대한 확장을 작성하여이 검사를 수행하는 데 필요한 코드의 양을 줄일 수 있습니다.

public static class Extensions
{
    public static void BeginInvokeIfRequired(this ISynchronizeInvoke obj, Action action)
    {
        if (obj.InvokeRequired)
            obj.BeginInvoke(action, new object[0]);
        else
            action();
    }
}

그리고 모든 스레드에서 텍스트 상자를 업데이트하는 것이 조금 더 간단 해집니다.

private void updatetextbox()
{
    textBox1.BeginInvokeIfRequired(() => textBox1.Text = "updated");
}

이 예제에서 사용 된 Control.BeginInvoke는 비동기식이므로 전달 된 대리자가 아직 실행되었는지 여부에 관계없이 Control.BeginInvoke를 호출 한 후에 오는 코드를 즉시 실행할 수 있습니다.

계속하기 전에 textBox1이 업데이트되었는지 확인해야하는 경우 대신 Control.Invoke를 사용하면 대리자가 실행될 때까지 호출 스레드가 차단됩니다. 많은 호출을하고 GUI 스레드가 호출 된 스레드가 보류 된 자원을 완료하거나 해제하기를 기다리고 있으면 응용 프로그램을 교착 상태로 만드는 경우이 접근 방식은 코드를 크게 줄입니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow