Control.Invoke с входными параметрами - PullRequest
13 голосов
/ 24 апреля 2009

Из того, что я нашел в C #, метод Control.Invoke требует, чтобы вы использовали делегата без входных параметров. Есть ли способ обойти это? Я хотел бы вызвать метод для обновления пользовательского интерфейса из другого потока и передачи ему строковых параметров.

Ответы [ 8 ]

22 голосов
/ 24 апреля 2009

Какую версию 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());
  }
}

Безопасный вызов кода теперь становится тривиальным.

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());

С C # 2.0 это становится менее тривиальным
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");
7 голосов
/ 02 мая 2012

Еще несколько возможностей:

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 предназначен для этих целей и имеет лучшую производительность.

6 голосов
/ 04 июня 2009

Как говорит Люк, используйте Control.Invoke, как это ...

Например, в форме:

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

public DelegatePassMessages passMessage;

В конструкторе:

passMessage = new DelegatePassMessages (this.MessagesIn);

Затем функция MessagesIn для получения данных:

public void MessagesIn(string name, int value)
{

}

Затем передать данные в вашу форму:

formName.Invoke(formName.passMessage, new Object[] { param1, param2});
1 голос
/ 08 июня 2013

Здесь вы можете использовать лямбда-выражения с расширением Invoke () + входной параметр.

Использование: action (STARS db)

_ccb.GetImagerFRU_PartNbr().Invoke(new Action<STARS>(dbase => _ccb.GetImagerFRU_PartNbr().Text = dbase.PartNumber(serial) ?? String.Empty), db);
1 голос
/ 04 июня 2009

Я думаю, что подход Самуила (превосходный) можно продвинуть еще больше:

Метод расширения:

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.
  });
}
0 голосов
/ 10 июля 2017
    private void ppTrace(string tv)
    {
        if (_Txb1.InvokeRequired)
        {
            _Txb1.Invoke((Action<string>)ppTrace, tv);
        }
        else
        {
            _Txb1.AppendText(tv + Environment.NewLine);
        }
    }
0 голосов
/ 01 марта 2012

Почему бы не

tvMatrix.Invoke((MethodInvoker) (() => {
    tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);
}));
0 голосов
/ 23 декабря 2010

Найден элегантный метод для .net 2.0 с анонимными методами, заключенными в делегат MethodInvoker. Таким образом, нет необходимости постоянно определять собственных делегатов. Пример:

    private void InitUI(Guid id, string typename)
    {
        MethodInvoker inv = delegate{tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);};
        tvMatrix.Invoke(inv);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...