c# - 크로스 - 컨트롤 이 자신 이 만들어진 스레드 가 아닌 스레드 에서 액세스 되었습니다




Windows Forms 컨트롤에 스레드 안전 액세스 메서드를 작성하는 가장 짧은 방법 (4)

이 기사의 내용 :

작성자는 다음 방법을 사용하여 Windows Forms 컨트롤에 대한 스레드로부터 안전한 호출을 만듭니다.

private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (this.textBox1.InvokeRequired)
    {    
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.textBox1.Text = text;
    }
}

같은 것을 성취 할 수있는 더 짧은 방법이 있습니까?


1) 익명 대리인 사용

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

2) AOP 방식

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

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

3) 람다 식 사용 (다른 사람들이 개괄).


내가 찾은 가장 짧은 해결책은 단추의 텍스트를 변경하는 것이 목표 인 아래의 단추 예제에 나와 있습니다.

    if (buttonX.InvokeRequired)
        buttonX.Invoke((Action)(() => buttonX.Text = "Record"));
    else
        buttonX.Text = "Record";

편집 : 나는 이것을 모범 사례로 생각하지 않을 것이라고 언급해야한다.

3.5를 사용하는 경우 다음과 같은 확장 메소드를 만들 수 있습니다.

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

이것은 기본적으로 Here 에서 가져옵니다 : Here

다음과 같이 사용하십시오.

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

물론 용도에 따라 확장 등을 수정하십시오.


C # 3.0 이상 :

일반적으로 확장 메서드가 있어야합니다. ISynchronizeInvoke 인터페이스 구현에서 항상 작업을 수행하려는 ISynchronizeInvoke 좋은 디자인 선택입니다.

확장 메서드에 전달할 매개 변수를 알지 못한다는 사실을 설명하기 위해 익명 메서드 (클로저)를 활용할 수도 있습니다. 클로저는 필요한 모든 상태를 캡처합니다.

// 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[] { });
}

그러면 다음과 같이 호출 할 수 있습니다.

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

여기서 클로저는 text 매개 변수 위에 있으며 상태는 확장 메서드에 전달 된 Action 대리자의 일부로 캡처되고 전달됩니다.

C # 3.0 이전 :

람다 식의 고급 스러움은 없지만 코드를 일반화 할 수는 있습니다. 꽤 많이 같지만 확장 메서드가 아닙니다.

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[] { });
}

그리고 익명 메소드 구문을 사용하여 호출합니다.

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




thread-safety