수색…
다른 스레드에서 양식 컨트롤에 액세스
컨트롤을 만든 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 스레드가 호출 된 스레드가 보류 된 자원을 완료하거나 해제하기를 기다리고 있으면 응용 프로그램을 교착 상태로 만드는 경우이 접근 방식은 코드를 크게 줄입니다.