2009-04-23 10 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); 
     } 
    } 
関連する問題