вызывать во время фонового рабочего

Мне нужно вызвать это: string input_ip_r = listView1.Items[lc].SubItems[1].Text; поэтому я использовал

if (InvokeRequired)
{
    this.Invoke(new MethodInvoker(function));
    return;
}

Это сработало, но теперь я поместил его в BackgroundWorker и с помощью этого

if (InvokeRequired)
{
    this.Invoke(new MethodInvoker(bw.RunWorkerAsync));
    return;
}

выдает ошибку, что вы можете запускать только BackgroundWorker по одному.

Итак, как мне вызвать, находясь в Backgroundworker?


person Dasher Labs    schedule 19.12.2012    source источник
comment
Хорошо, я в замешательстве. a) зачем помещать код для доступа к пользовательскому интерфейсу в фоновый рабочий процесс? b) вы пытаетесь запустить bw.RunWorkerAsync из bw.DoWork?   -  person Mike Park    schedule 20.12.2012
comment
Что ты имеешь в виду? Предполагается, что первый код запускается из фонового потока (вызывая поток пользовательского интерфейса). Второй код выглядит так, как будто он пытается вызвать фоновый поток.   -  person Mario S    schedule 20.12.2012
comment
Строка должна быть вызвана, и я не могу понять, как это сделать во время фонового рабочего процесса, новый MethodInvoker пытается запустить ее во второй раз.   -  person Dasher Labs    schedule 20.12.2012


Ответы (2)


Я не совсем уверен, как вы хотите использовать значения, но просто для примера вы можете легко сделать это в потоке BackgroundWorker:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    string input_ip_r = "";
    this.Invoke(new Action(() => 
    {
        // Don't know what "lc" is (a loop variable?)
        input_ip_r = listView1.Items[lc].SubItems[1].Text;
    }));
}

См. этот ответ для других способов сделать то же самое (это для >= .Net 3.5)

person Mario S    schedule 19.12.2012
comment
Я рад, что это сработало для вас =) Однако помните, что это всего лишь один из возможных способов. В ответе @Servy есть моменты, которые также следует учитывать. - person Mario S; 20.12.2012

1) Не указывайте RunWorkerAsync в качестве вызываемого метода. На самом деле это не тот метод, о котором вы думаете. То, что вы действительно должны поместить там, выглядит примерно так:

this.Invoke(new MethodInvoker(MethodToUpdateUI));

MethodToUpdateUI должен быть какой-то новый метод, который вы создаете, который специально делает все обновления пользовательского интерфейса, которые должны быть сделаны в этом контексте.

2) Нет необходимости в InvokeRequired. Вы находитесь в фоновом потоке. Вызов всегда будет требоваться.

Честно говоря, весь паттерн if(invoke required) call myself else do stuff — странная конструкция, которая мне не нравится. InvokeRequired следует использовать довольно редко. Вы почти всегда должны знать, находитесь ли вы в потоке пользовательского интерфейса или в фоновом потоке, если нет, скорее всего, что-то не так (либо вы всегда находитесь в одном, либо в другом, и вы просто не знаете, в каком, или это не должно быть недетерминированным). Обычно это означает наличие методов, которые должны выполняться в потоке пользовательского интерфейса. Если вы уже находитесь в потоке пользовательского интерфейса, вы просто вызываете их, если вы находитесь в фоновом потоке и знаете это, тогда вы сначала вызываете Invoke.

Кроме того, Invoke работает просто отлично, даже если вы вызываете его, когда вы уже находитесь в потоке пользовательского интерфейса, поэтому на самом деле нет серьезных негативных последствий для простого вызова Invoke независимо от того, находитесь ли вы в фоновом потоке или уже в пользовательском интерфейсе. нить.

3) Обычно код для решения бизнес-задач лучше отделить от кода пользовательского интерфейса. Это запах кода, который нужно вызывать из обработчика DoWork. Если это почти конец, вам, вероятно, следует добавить обработчик событий в RunWorkerCompleted. Если вы периодически вызываете это, чтобы обновить пользовательский интерфейс с ходом работы работника, вы должны использовать ReportProgress и обрабатывать событие ProgressReported. Чтобы получить информацию из пользовательского интерфейса для использования в длительной задаче, вы должны получить к ней доступ перед запуском фоновой задачи. Для исключительных случаев, которые не являются ни одним из них, может быть уместно использовать Invoke, но остальные случаи должны быть редкими.

person Servy    schedule 19.12.2012
comment
Мне нужно установить это значение listView1.Items[lc].SubItems[1].Text внутри фонового рабочего без вызовов перекрестных потоков - person Dasher Labs; 20.12.2012
comment
@ user1335937 Хорошо. Это то, что мой ответ помогает вам решить. - person Servy; 20.12.2012
comment
Я новичок в С#, поэтому у меня есть цикл для получения каждого элемента списка из подпункта 2 и как его использовать внутри фонового рабочего? - person Dasher Labs; 20.12.2012
comment
@user1335937 user1335937 Удалите все элементы из списка и поместите их в структуру данных, например List или массив. Затем сохраните это как поле частного экземпляра и используйте его в фоновом рабочем процессе. Таким образом, вы не получаете доступ к пользовательскому интерфейсу из фонового рабочего. - person Servy; 20.12.2012