2009-04-23 3 views
12

C#에서 찾은 것으로부터 Control.Invoke 메서드를 사용하면 입력 매개 변수없이 대리자를 사용해야합니다. 이 주위에 어떤 방법이 있습니까? 다른 스레드에서 UI를 업데이트하고 문자열 매개 변수에 전달하는 메서드를 호출하고 싶습니다.Control.Invoke with input 매개 변수

답변

22

사용중인 C# 버전은 무엇입니까? C# 3.5를 사용하는 경우 클로저를 사용하여 매개 변수를 전달하지 않아도됩니다.

C# 3.5
public static class ControlExtensions 
{ 
    public static TResult InvokeEx<TControl, TResult>(this TControl control, 
              Func<TControl, TResult> func) 
    where TControl : Control 
    { 
    return control.InvokeRequired 
      ? (TResult)control.Invoke(func, control) 
      : func(control); 
    } 

    public static void InvokeEx<TControl>(this TControl control, 
             Action<TControl> func) 
    where TControl : Control 
    { 
    control.InvokeEx(c => { func(c); return c; }); 
    } 

    public static void InvokeEx<TControl>(this TControl control, Action action) 
    where TControl : Control 
    { 
    control.InvokeEx(c => action()); 
    } 
} 

로 안전하게 현재 코드를 호출하면 단순해진다. C# 2.0

this.InvokeEx(f => f.label1.Text = "Hello World"); 
this.InvokeEx(f => this.label1.Text = GetLabelText("HELLO_WORLD", var1)); 
this.InvokeEx(() => this.label1.Text = DateTime.Now.ToString()); 

그것은 간단하게 사용
public class MyForm : Form 
{ 
    private delegate void UpdateControlTextCallback(Control control, string text); 
    public void UpdateControlText(Control control, string text) 
    { 
    if (control.InvokeRequired) 
    { 
     control.Invoke(new UpdateControlTextCallback(UpdateControlText), control, text); 
    } 
    else 
    { 
     control.Text = text; 
    } 
    } 
} 

덜 사소한 될,하지만 당신은 더 많은 매개 변수에 대한 더 많은 콜백을 정의해야합니다.

this.UpdateControlText(label1, "Hello world"); 
1

나는 사무엘의 (우수) 접근 방식은 더 밀어 수 있다고 생각 :

확장 방법 :

public static void ExecuteAsync<TControl>(this TControl control, Action action) 
where TControl : Control 
{ 
    new Thread(() => 
    { 
    control.Invoke(action); 
    }) 
    .Start(); 
} 

양식 코드 :

private void doStuff() 
{ 
    this.ExecuteAsync(() => 
    { 
    // Do your stuff in a separate thread 
    // but having full access to local or instance variables. 

    // No (visible) threading code needs to be used here. 
    }); 
} 
6

루크로 말한다, Control.I 사용 이런 nvoke ... 형태 예

: 다음

passMessage = new DelegatePassMessages (this.MessagesIn); 

데이터를 수신 할 MessagesIn 기능 :이어서

public void MessagesIn(string name, int value) 
{ 

} 

를 생성자에서

public delegate void DelegatePassMessages(string name, int value); 

public DelegatePassMessages passMessage; 

양식에 데이터를 전달하는 방법 :

formName.Invoke(formName.passMessage, new Object[] { param1, param2}); 
0

MethodInvoker 대리인에 래핑 된 익명 메서드를 사용하여 .net 2.0에 대한 우아한 메서드를 찾을 수 있습니다. 그렇게하면 항상 자신의 위임자를 정의 할 필요가 없습니다.예 :

private void InitUI(Guid id, string typename) 
    { 
     MethodInvoker inv = delegate{tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);}; 
     tvMatrix.Invoke(inv); 
    } 
0

tvMatrix.Invoke((MethodInvoker) (() => { 
    tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename); 
})); 
7

좀 더 가능성 :

this.Invoke(new MethodInvoker(() => this.DoSomething(param1, param2))); 

또는

this.Invoke(new Action(() => this.DoSomething(param1, param2))); 

또는

this.Invoke(new Func<YourType>(() => this.DoSomething(param1, param2))); 

첫 번째 옵션이 가장 좋습니다. MethodInvoker는 그 목적을 위해 개념화되어 더 나은 성능을 제공하기 때문에 최상의 옵션입니다.

1

여기에 Invoke() 확장 + 입력 매개 변수가있는 람다 식을 사용합니다.

사용 : 액션 (STARS의 데시벨)

_ccb.GetImagerFRU_PartNbr().Invoke(new Action<STARS>(dbase => _ccb.GetImagerFRU_PartNbr().Text = dbase.PartNumber(serial) ?? String.Empty), db); 
0
private void ppTrace(string tv) 
    { 
     if (_Txb1.InvokeRequired) 
     { 
      _Txb1.Invoke((Action<string>)ppTrace, tv); 
     } 
     else 
     { 
      _Txb1.AppendText(tv + Environment.NewLine); 
     } 
    }