2009-04-02 3 views
1

Я создаю пользовательский интерфейс для программы, и я не могу понять, почему мой индикатор выполнения не станет видимым после нажатия кнопки конвертирования.C# Winforms Как обновить toolStrip в функции

private void convertButton_Click(object sender, EventArgs e) 
{ 
    toolStripProgressBar.Visible = true; 

    ... 

    toolStripProgressBar.Visible = false; 
} 

Я столкнулся с аналогичной проблемой с Tkinter в Python, и мне пришлось вызвать функцию для обновления холостых задач. Есть ли способ сделать это с формами окон без использования потоков?

Редактировать: На боковой ноте это индикатор выполнения в toolStrip, который также содержит метку, которая обновляется с текстом строки состояния. Есть ли способ получить ярлык с левой стороны и индикатор выполнения на другом, а не справа друг от друга слева?

ответ

4

Ну, это способ сделать это без использования потоков (Application.DoEvents), но я сильно рекомендуем вам использовать его. Re-entrancy является неприятным, и вы действительно не хотите, чтобы потоки пользовательского интерфейса были связаны вообще.

Использовать BackgroundWorker вместо этого - это легко, и это довольно много. рассчитан на для индикаторов прогресса. Это избавляет вас от использования отдельного потока и сообщает о прогрессе в потоке пользовательского интерфейса. Нет необходимости в Control.Invoke и т. Д. - это позаботится об этом для вас.

Есть lots of tutorials for BackgroundWorker - это не должно занять слишком много времени, чтобы идти с ним.

+0

Предполагаете, вы рекомендуете перемещать длительный процесс в отдельный поток, чтобы поддерживать постоянный пользовательский интерфейс? –

+0

Да - это то, что помогает BackgroundWorker. –

+0

Цените помощь. Я надеялся избежать потоков, поскольку они довольно сложны вручную, и это простой пользовательский интерфейс, но это звучит прекрасно. Благодарю. –

1

За вопрос, который вы попросили сделать это БЕЗ потоков, то есть сделать это с помощью Application.DoEvents() ;. (Просто добавьте этот вызов сразу после установки индикатора выполнения как видимого.)

Теперь я согласен с Джоном Скитом, хотя BackgroundWorker - лучший способ сделать это, но он использует отдельный поток.

1

Вам необходимо выполнить свой процесс в потоке отдельно от потока пользовательского интерфейса, а затем периодически отправлять отчет в поток пользовательского интерфейса с его прогрессом. Если ваша операция преобразования работает внутри потока пользовательского интерфейса, она просто перестает отвечать, пока операция не будет завершена.

1

Я предполагаю, что проблема заключается в том, что "..." в вашем коде является долговременным процессом. Обновления пользовательского интерфейса не являются мгновенными, но должны проходить через очередь сообщений в окнах, а затем окрашиваться на экран. Очередь перекачивается, и живопись происходит в том же потоке, что и ваши события.

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

Один из способов сделать это с помощью элемента управления BackgroundWorker.

1

Индикатор выполнения может отображаться только тогда, когда ему разрешено рисовать, что происходит во время обработки сообщений. Обработка сообщений обычно не может произойти, когда вы находитесь в середине обработчика событий. Если вы хотите, чтобы индикатор выполнения отображался, вам нужно установить visiblitity в true, запустить фоновый поток, чтобы завершить работу и вернуться из обработчика.

1

Здесь идут две ссылки, пытаясь объяснить, как это работает: (1)(2)

Теперь, я попытаюсь объяснить, как в ближайшее время, как я могу. Большинство из того, что происходит внутри приложения Windows Form, происходит в одном потоке, обычно выполняется один и тот же поток Main(). Если вы откроете Program.cs, вы увидите, что Main() имеет строку, которая выглядит следующим образом:

Application.Run(new Form1()); 

Если вы отлаживаете приложение в любой момент и проверяете стек вызовов, вы увидите, что он вернется к этому методу Run. Это означает, что приложение Windows Forms на самом деле является непрерывным запуском метода Run. Итак, что делает Run? Run запускает очередь сообщений, через которые Windows отправляет ей сообщения. Затем они отправляют эти сообщения в правильные элементы управления, которые сами выполняют такие вещи, как добавление текста, который соответствует нажатой клавише, перерисовывают себя и т. Д. Обратите внимание, что все это происходит во время и бесконечный цикл, идущий рядом с одним потоком, так что погода вы печатаете или просто перемещая окно вокруг, грузы этих сообщений передаются в приложение, которое, в свою очередь, обрабатывает их и реагирует соответственно, все в одном потоке. Элементы управления также могут отправлять сообщения в очередь через очередь, и даже вы можете размещать сообщения в насосе через Control.BeginInvoke. Одна из вещей, которую эти средства управления делают, - это поднять события в соответствии с тем, что происходит. Таким образом, если вы нажмете кнопку, код, который вы написали для обработки этого клика, в конечном счете и косвенно будет запущен методом Application.Run.

Теперь, что происходит с вашим кодом, так это то, что, хотя вы меняете видимый статус вашего индикатора выполнения на видимый, а затем обновляете его значение, вы меняете его видимость на false, все в одном методе. Это означает, что только после того, как вы покинете метод, Application.Run() сможет продолжить итерацию и потребление очереди сообщений, эффективно попросив индикатор выполнения обновить его отображение. Когда это произойдет, вы уже оставили видимость индикатора выполнения на false, последнее, что вы сделали до выхода из метода. DoEvents() - это быстрый и грязный обходной путь к вашей проблеме, поскольку он читает сообщения в очереди и обрабатывает их. Я действительно не чувствую себя комфортно, используя его, так как он может вызвать проблемы с появлением.

Использование потоков является хорошим решением, но я бы рекомендовал использовать ThreadPool-поток вместо пользовательского потока в подобной ситуации, поскольку я склонен использовать пользовательские потоки только в тех случаях, когда у меня ограниченное число длинноволновых потоков и мне нужно контролировать их жизненные циклы. Самый простой и практичный способ использования потоков - использовать компонент BackgroundWorker, хотя я бы рекомендовал понять, как делать многопоточность Windows Forms с делегатами, если вы хотите действительно понять, что происходит.

+0

Спасибо за нарушение. Решение BackgroundWorker работало, и я буду рассматривать делегатов в будущем. –

0

Мое решение - вызвать обновление на полосе состояния.
Я считаю, что это приводит к тому, что поток пользовательского интерфейса перекрашивает полосу состояния.

toolStripStatusBar1.PerformStep(); 
statusStrip1.Refresh(); 

Это для .NET 4.0. Несмотря на то, что этот вопрос старый, это был первый случай, который я нашел в этой статье.

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