2015-10-04 8 views
1

изменить: Application.DoEvents(); это сделало это. найти здесь: Force GUI update from UI Threadкак сделать форму задержки дисплея

C#, winforms. Я хочу увеличить число с шагом 1 и иметь эти приращения, показанные внутри списка, так что пользователь видит подсчет числа (например, от 10 до 15).

У меня есть еще одна кнопка, которая увеличивается при нажатии на 1 при использовании одного и того же дисплея(). он отлично работает и обновляет дисплей, как ожидалось.

я попробовал эти коды (укороченные для экономии места здесь):

(1)

for (int i = 0; i < 5; i++) 
{ 
    var t = Task.Run (async() => 
    { 
     myInt++; 
     await Task.Delay(300); 
     display(); //forces screen refresh 
    }); 
} 

(2)

for (int i = 0; i < 5; i++) 
{ 
    var t = Task.Run (() => 
    { 
     myInt++; 
     Task.Delay(300).Wait; 
     display(); 
    }); 
    //t.Wait(); //causes "An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll" 
} 

(3)

for (int i = 0; i < 5; i++) 
{ 
    myInt++; 
    display(); 
    System.Threading.Thread.Sleep(300); 
} 

(4)

Stopwatch stopwatch = new Stopwatch(); 
for (int i = 0; i < 5; i++) 
{ 
    stopwatch.Restart(); 
    while (true) 
    { 
     if (stopwatch.ElapsedMilliseconds >= 300) 
     { 
      break; 
     } 
    } 
stopwatch.Stop(); 
myInt++; 
display(); 
} 

всего использовать это:

private void display() 
{ 
    myListView.Items.Clear(); 
    myListView.Items.Add(new ListViewItem(new[] { myInt })); 
} 

(1) и (2) увеличить число на 5, но дисплей не обновляется вообще. он показывает, когда дисплей обновляется какой-либо другой функцией.

(3) и (4) увеличивают число на 5, но дисплей обновляется только примерно через 1500 мс, дисплей пропускает одиночные шаги и отображает только конечный результат (например, 15).

любые предложения, чтобы сделать эту работу? могу ли я заставить обновление в функции display() как-то?

Почему t.Wait(); вызвать исключение? (Я нашел код задачи где-то в сети)

редактировать:

(5)

private void team_comm_btn_all_Click(object sender, EventArgs e) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
      await Run(i); //error 74 see below 
    } 
} 

private async Task Run(int i) 
{ 
    myInt++; 
    display(); 
    await Task.Delay(300); 
} 

AWAIT Run (I); дает следующее: Ошибка 74 Оператор «ожидание» может использоваться только в асинхронном методе. Подумайте о маркировке этого метода с помощью модификатора «async» и измените его тип возврата на «Задача».

Выполнение «Run (i)» вместо этого дает предупреждение о том, что «await» отсутствует ... в этом случае он скомпилируется и увеличивается на 5 без задержки.

(6)

private void team_comm_btn_all_Click(object sender, EventArgs e) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     var task = Task.Run(async() => 
     { 
      await Run(i); 
     }); 
    } 
} 

private async Task Run(int i) 
{ 
    myInt++; 
    display(); 
    await Task.Delay(300); 
} 

увеличивается на 5, но не обновляет индикацию на всех.

+0

http://stackoverflow.com/questions/19028374/accessing-ui-controls-in-task-run-with-async-await- on-winforms –

+0

этот поток не охватывает все, что я пытался, и я не нашел там ничего, чтобы решить мою проблему (см. править выше). хотя это улучшило мое понимание задач =) – letsdance

+0

Да, я не голосовал, чтобы закрыть как дубликат, потому что я не был уверен, что это та же проблема. Не удалось выполнить WinForms еще задолго до выхода асинхронного ПО. Тот факт, что «ничего» не происходит, тогда вы вдруг видите, что последнее значение похоже на то, что очередь сообщений Windows не обрабатывается. Вы получите это поведение, если вы, например. иметь цикл, который обновляет пользовательский интерфейс в обычном обработчике событий. Не знаю, как это относится к вашей ситуации. –

ответ

0

Обычно для этого вы должны использовать System.Windows.Forms.Timer. Но async/await делает такие вещи тривиальными, как только вы это понимаете (и внимательно прочитайте предупреждения и сообщения об ошибках компилятора). Вкратце, (5) - это способ пойти с небольшой модификацией, разрешающей ошибку компилятора.
Но пусть начнется с самого начала.Предполагая, что вы сначала написать нормальный синхронный вариант, как это (в основном ваш (3))

private void team_comm_btn_all_Click(object sender, EventArgs e) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     if (i != 0) System.Threading.Thread.Sleep(300); 
     myInt++; 
     display(); 
    } 
} 

просто видеть, что пользовательский интерфейс не обновляется. Таким образом, вы решили превратить его в асинхронном, который с помощью async/await проста замена Thread.Sleep с Task.Delay как этот

private void team_comm_btn_all_Click(object sender, EventArgs e) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     if (i != 0) await Task.Delay(300); 
     myInt++; 
     display(); 
    } 
} 

Но теперь он не компилировать со следующей ошибкой

Error 74 ' ожидание "может использоваться только в асинхронном методе. Подумайте о маркировке этого метода с помощью модификатора «async» и измените его тип возврата на «Задача».

Сообщение достаточно ясное. Вы должны отметить свой метод с помощью ключевого слова async. Что касается другой рекомендации по изменению типа возврата на Task, как правило, вы должны принять это во внимание, но поскольку вы находитесь внутри обработчика событий, то есть метода, подпись которого не может быть изменена, вы можете игнорировать эту часть - это точный случай, почему async void разрешено.

В заключение, окончательный код будет выглядеть следующим образом

private async void team_comm_btn_all_Click(object sender, EventArgs e) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     if (i != 0) await Task.Delay(300); 
     myInt++; 
     display(); 
    } 
} 
+0

thx, проверит это иногда. Application.DoEvents() отлично работал в этом случае, но, похоже, я сталкиваюсь с подобными проблемами в других точках кода, где более элегантное решение будет лучше. – letsdance