MethodInvoker + лямбда + аргументы + операция CrossThread - PullRequest
2 голосов
/ 24 апреля 2011

Я использую это, чтобы изменить что-то в другой теме:

        MethodInvoker m = () => { login_submit.Text = "Login"; };
        if (InvokeRequired)
        {
            BeginInvoke(m);
        }
        else
        {
            Invoke(m);
        }

это работает нормально.

Как я могу передать аргументы этому выражению lamba?

Я хочу сделать вот что:

        MethodInvoker m = (string txt) => { login_submit.Text = txt; };
        if (InvokeRequired)
        {
            BeginInvoke(m); // I need to pass txt string in some way here.
        }
        else
        {
            Invoke(m); // I need to pass txt string in some way here.
        }

Ответы [ 4 ]

2 голосов
/ 23 февраля 2014

Если это обычный сценарий для вас, я предлагаю написать метод расширения:

public static class ControlExtensions
{
  public static void EnsureInvokeAsync(this Control control, Action action)
  {
     if (control.InvokeRequired) control.BeginInvoke(action);
     else action();
  }
}

class MyControl : UserControl
{
    void M(string s)
    {
       // the lambda will capture the string in a closure
       // the compiler does all the hard work for you
       this.EnsureInvokeAsync(() => _button.Text = s);
    }
}

Кроме того, вы должны изучить использование BackgroundWorker или задач для асинхронных операций.

1 голос
/ 24 апреля 2011

Если InvokeRequired имеет значение false, вам не нужно беспокоиться о вызове чего-либо вообще - вы уже на правильном пути.

Лучшим решением может быть что-то вроде этого:

public delegate void InvokerDelegate(string data);
public void DoStuff(string data){
  login_submit.Text = data;
}

, а затем при вызове он делает:

if (InvokeRequired){
  Invoke(InvokerDelegate(DoStuff), "something");
}
else{
  DoStuff("Something");
}

Довольно распространенный шаблон, который вы увидите, это сделатьчто-то вроде этого для функций, которые манипулируют GUI в многопоточной среде

public delegate void InvokerDelegate();
public void DoGuiStuff(){
  if (login_submit.InvokeRequired){
    login_submit.Invoke(InvokerDelegate(DoGuiStuff));
    return;  
  }

  login_submit.Text = "Some value";
}

Если вы используете вышеприведенный шаблон, функция проверяет, требуется ли вызов, и если так, то вызывает себя в нужном потоке.Затем он возвращается.Когда он вызывает себя, проверка того, требуется ли вызов, возвращает false, поэтому он не беспокоится о повторном вызове самого себя - он просто запускает код.

Редактировать: я просто вернулся к winforms и попытался использовать этошаблон только потратить пару разочаровывающих минут, пытаясь понять, почему я не могу вызвать лямбду.Я подумал, что лучше вернуться и обновить этот ответ, чтобы добавить необходимый кастинг на тот случай, если кто-то еще попытается его использовать.

1 голос
/ 24 апреля 2011

MethodInvoker - это тип делегата, который не имеет никаких параметров. Если я вас правильно понимаю, вы можете сделать это так:

string txt = "some text";
MethodInvoker m = () => { login_submit.Text = txt; };
0 голосов
/ 24 апреля 2011

Вы можете использовать замыкания для передачи значения в тело лямбды.

string value = "Login";
MethodInvoker m = () => { login_submit.Text = value; };
if (InvokeRequired)
{
    BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
    Invoke(m); // I need to pass txt string in some way here.
}

или вы можете использовать данные члена класса

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...