2017-02-02 15 views
0
public class Form1 
{ 
    public delegate void SetStatus (string status); 
    public event SetStatus SetStatusHandler; 

    public BackgroundWorker bw = new BackgroundWorker(); 

    public Form1() 
    { 
     tbxResult.Text = "Assign text Ok"; 

     SetStatusHandler += delegate(string status) 
      { 
       tbxResult.Text = status; // can not assign 
      }; 

     bw.DoWork += backgroundWorker_DoWork; 
     bw.RunWorkerAsync(); 

    } 

    void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     var status = "assign some value"; 
     SetStatusHandler(status); 
    } 
} 

Во-первых, я попытался установить значение для текстового поля tbxResult на главном потоке внутри BackgroundWorker, но это не сработало, то я использую делегата присвоить значение текстового поля из основной нити, но он тоже не работает ...Невозможно присвоить значение для текстового поля в BackgroundWorker (C# WinForm)

Пожалуйста, помогите мне ... что не так?

+0

Вы не пытаетесь установить его из основного потока. Вызов делегата не переключает поток. Установите 'backgroundWorker.WorkerReportsProgress' в' true', подпишитесь на событие backgroundWorker.ProgressChanged и вызовите 'backgroundWorker.ReportProgress()' вместо 'SetStatusHandler'. Btw: backgroundworker отчасти устарел, попробуйте вместо этого использовать 'async/await'. –

+0

Для этой цели вы должны вызвать 'Control.Invoke'. Читайте для получения более подробной информации [Control.Invoke] (https://msdn.microsoft.com/en-us/library/zyzhdc6b (v = vs.110) .aspx) –

ответ

0

Нам нужно снова вызовите метод, используя основной поток пользовательского интерфейса. Посмотрите для получения дополнительной информации Usage of MethodInvoker in C#

tbxResult.Invoke((MethodInvoker) delegate 
    { 
     tbxResult.Text = status; 
    }); 
+1

Также лучше написать некоторое описание. –

+0

Да, нам нужно снова вызвать метод, используя основной поток пользовательского интерфейса. Посмотрите дополнительную информацию [Использование MethodInvoker в C#] (http://thebrainyprofessionals.com/2013/03/30/использование-оф-methodinvoker-в-с /) –

0

Надеюсь, что логика имеет смысл. Но объявление делегата неверно, вы должны указать тип возврата в объявлении SetStatus, чтобы заставить его работать. Таким образом, изменить декларацию, как следующее:

public delegate void SetStatus (string status); 

Тем не менее, вы получаете исключение (IllegalCrossThreadCallException, как René Vogt упоминалось в комментарии) означает, что вы можете определить обработчик события, как следующее:

SetStatusHandler += delegate(string status) 
{ 
    tbxResult.Invoke(new MethodInvoker(delegate 
    { 
     tbxResult.Text = status; 
    })); 

}; 
+0

@ RenéVogt: но оно обновит текстовое поле с помощью '" присваивать некоторое значение "' –

+0

Контекст проблемы другой. –

+0

@ un-lucky: Спасибо! Не могли бы вы рассказать мне разницу между «tbxResult.text = status» и «tbxResult.Invoke (новый MethodInvoker (делегат ...»). Первый выполняется в backgroundworker thead, а второй - в основном потоке, правильно? –

0

В общем, я думаю, что BackgroundWorker является устаревшим, и это лучше использовать async/await шаблон. Но это был бы слишком широкий ответ.

Итак, немедленный ответ: обработчик событий не выполняется в потоке пользовательского интерфейса, но все равно на потоке рабочего фона. Обычный способ reinvoke действия на Ui нити из фона работника использовать это ReportProgress метод:

public Form1() 
{ 
    tbxResult.Text = "Assign text Ok"; 
    bw.DoWork += backgroundWorker_DoWork; 
    bw.WorkerReportsProgress = true; 
    bw.ProgressChanged += (sender, e) => tbxResult.Text = (string)e.UserState; 
    bw.RunWorkerAsync(); 
} 

void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    var status = "assign some value"; 
    bw.ReportProgress(0, status); 
} 

ReportProgress() вызывает ProgressChanged событие на UI нити, так что вы можете назначить текст в текстовое поле. Не забудьте установить WorkerReportsProgress на номер true.

0

Используйте InvokeRequred как это (или с делегатом):

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     if (textBox1.InvokeRequired) 
     { 
      textBox1.Invoke((MethodInvoker) delegate { textBox1.Text = @"AAAAAA"; }); 
     } 
     else 
     { 
      textBox1.Text = @"AAAAAA"; 
     } 
    } 

пс: также см Anonymous method in Invoke call