2012-01-17 3 views
2

У меня есть два вопроса об использовании BackgroundWorker:Использование BackgroundWorker в C#?

1) Допустим, у вас есть Функция A и B. Функция Функция A создает BackgroundWorker, который работает Функция B. Таким образом, BackgroundWorker теперь работает функцию B в отдельном потоке. Функция B - бесконечный цикл while, который я намерен запускать в течение длительного времени. После того, как функция A использует BackgroundWorker, она возвращается. Итак, теперь, когда функция, инициировавшая BackgroundWorker (Function A), вернулась, продолжает ли поток BackgroundWorker работать в фоновом режиме? Или он прекращает выполнение функции B, поскольку возвращаемая им функция вернулась? Если это прекратится, как я могу сделать так, чтобы функция B продолжала работать даже после того, как функция A вернулась?

2) Мне нужно получить доступ к элементам Window Forms (т. Е. Текстовому поле) из отдельного потока, созданного BackgroundWorker. Однако, если я попытаюсь получить доступ к элементам Window Forms из потока, который не является основным, я получаю ошибку поперечной потоковой передачи. Как я могу безопасно обращаться к элементам Window Forms из отдельного потока? Мне в основном нужно обновлять текстовое поле из отдельного потока. Я знаю, что у BackgroundWorker есть член под названием «RunWorkerCompleted», и он запускается после завершения BackgroundWorker. Это позволяет мне получить доступ к элементам Window Forms. Однако мне нужно получить доступ к элементу Window Forms во время моего потока, а не после его завершения. Как я могу получить доступ к ним безопасно через поток? Если это невозможно, то какие другие возможные решения проблемы?

ответ

4

1) BackgroundWorker будет продолжать работать после возвращения функции A.

2) Создайте обработчик событий ProgressChanged, который обновляет текстовое поле и имеет BackgroundWorker вызов ReportProgress всякий раз, когда вы хотите изменить текст. Конечно, вам нужно будет установить BackgroundWorker свойство, которое может прочитать событие ProgressChanged. Это работает, потому что обработчик события ProgressChanged вызывается в потоке пользовательского интерфейса.

+0

Спасибо. Я использовал ProgressChanged, но он по-прежнему дает мне ошибку поперечной резьбы. Любая идея почему? – fdh

+0

Вы (@Farhad) попробовали фрагмент кода, данный мной? –

+0

@Amir Palsapure Спасибо за помощь. Ваш ответ слишком сложный для меня (без вашей вины), и это просто кажется немного проще, поэтому я решил попробовать. Я только начал C#, поэтому этот ответ кажется немного более понятным. Еще раз спасибо за вашу помощь. – fdh

1

Ответ Джима правильный.

Во второй части вы сказали

Мне нужно получить доступ окна Forms Элементы (т.е. TextBox) из отдельного потока, созданного BackgroundWorker.

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

public static class ControlExtensions 
{ 
    public static void Invoke(this Control control, Action action) 
    { 
     if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null); 
     else action.Invoke(); 
    } 
} 

Теперь, когда вы обращаетесь к текстовому полю с вашей Non-UI нити , вам необходимо сделать это следующим образом:

txtBox.Invoke(() => { txtBox.Text = "Text Changed from Non-UI thread"; }); 

Надеюсь, это вам поможет.

1

Что касается второго вопроса:

Даже я столкнулся с той же проблемой раз. Поэтому используется метод _DoWork.
Вот как это работает для меня

private void bgwLongTask_DoWork(object sender, DoWorkEventArgs e) 
{ 

    my long task 
    { 
     //in between the long task, i want to udpate the datagrid view dataGridView1 

     if (dataGridView1.InvokeRequired) 
     dataGridView1.Invoke(myGridBindDelegate); 
     else 
     BindDataToGrid(); 
    } 
} 

Здесь myGridBindDelegate является делегат, который вызывает метод связывания вид DataGrid.

delegate void GridBindDelegate(); 
    GridBindDelegate myGridBindDelegate; 
    myGridBindDelegate = BindDataToGrid; 

    private void BindDataToGrid() 
    { 
     dataGridView1.DataSource = dt; //dt is a datatable which is public 
     dataGridView1.Refresh(); 
    } 

Работал для меня.

Смежные вопросы