Задать вопрос

Доступ к контролу Windows Forms из другого потока (C#)?

Пробую писать программу, основной код которой будет выполняться в другом потоке и добавлять данные в ListBox по ходу работы.


Log — объект типа ListBox.


Создание потока:
private void bGo_Click(object sender, EventArgs e)
{
    ...
    Log.Items.Add("Старт");
    Thread t = new Thread(Download);
    t.Start();
    t.Join();
    ...
}



Работа потока:
void Download()
{
    for (int i = 0; i <= 2; i ++)
    {
        for (int j = 0; j <= 1000; j += 100)
        {
            Thread.Sleep(100);
            //реальный код слал запросы в сеть, 
            //т.е. большую часть времени простаивал
            WriteToLog("test");
        }
    }
}



Работа с ListBox'ом:
void WriteToLog(string message)
{
    if (Log.InvokeRequired)
    {
        Log.BeginInvoke(new Action<string>((s)
            => Log.Items.Add(s)), message);
    }
    else
    {
        Log.Items.Add(message);
    }
}



В результате выводится «Старт», затем трёхсекундная пауза и 30 «test», хотя всё это должно выводиться по ходу работы. Если заменить BeginInvoke на Invoke, программа зависает на этой строке на неопределённое время. Как сделать нормальный вывод?
  • Вопрос задан
  • 30542 просмотра
Подписаться 6 Оценить 2 комментария
Решения вопроса 1
VenomBlood
@VenomBlood
Раз используется .net 4.0 — то вместо потоков лучше использовать задачи:
Task task = new Task(Download);
task.ContinueWith(CodeAfterJoin);
task.Start();

Только тут надо учитывать, что продолжение запустится в своем собственном потоке.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 5
Толковое описание потоков тут www.rsdn.ru/article/dotnet/CSThreading1.xml

>Если заменить BeginInvoke на Invoke, программа зависает на этой строке на неопределённое время. Как сделать нормальный вывод?

Потому что вы используете t.Join();
Ответ написан
@afsherman
Как уже сказали выше, с Join() ничего работать не будет, т.к. вы ждёте завершения потока.
А вообще посмотрите в сторону асинхронного программирования и класса BackgroundWorker.
msdn.microsoft.com/en-us/library/ms228969.aspx
Ответ написан
Комментировать
Desiderata
@Desiderata
Попробуйте так:
delegate void WriteToLogDelegate(string message);
void WriteToLog(string message)
{
    if (Log.InvokeRequired)
    {
         var writeToLog = new WriteToLogDelegate(WriteToLog);
         Log.Invoke(writeToLog, message);
    }
    else
    {
        Log.Items.Add(message);
    }
}
Ответ написан
private delegate void UpdateListBox(string test);
static object locker = new object();

private void UpLB(string test)
{
lock (locker)
{
Log.Items.Add(test);
}
}

//После чего вызываете
this.Invoke(new UpdateListBox(this.UpLB),new object[] { m.Message});

Попробуйте так
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы