private void MainForm_Load(object sender, EventArgs e)
{
ProgressForm progressForm = new ProgressForm();
progressForm.Show();
BgWorker.RunWorkerAsync();
}
Прогресс бары и выполнение операций в фоне при старте приложения/формы
Наверняка у всех возникала необходимость выполнения действий требующих времени. (всяких операций ввода-вывода, обращения к бд) и чтоб при этом форма не повисало и отображала какой-нить прогрес бар.
В случае когда это надо сделать по нажатию какой-нить кнопки - всё понятно, используем BackGroundWorker, или потоки и Control.Invoke().
Так вот, предположим это действие надо выполнить при запуске главной формы: перед тем как она нарисуеться вывести окошко с прогрес баром.
Делаю так:
Код:
В этом случае метод завершиться и тогда форма нарисуеться заурыв форму с прогессом. Можно конечно её закрыть в Shown, но она всёравно успеет нарисоваться и вапще это как-то неправильно. Тогда можно так:
Код:
private void MainForm_Load(object sender, EventArgs e)
{
ProgressForm progressForm = new ProgressForm();
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
progressForm.Show();
// вызоветься метод который будет progressForm менять, а потом разлочит autoResetEvent
BgWorker.RunWorkerAsync();
waitForGetBinderNames.WaitOne();
}
{
ProgressForm progressForm = new ProgressForm();
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
progressForm.Show();
// вызоветься метод который будет progressForm менять, а потом разлочит autoResetEvent
BgWorker.RunWorkerAsync();
waitForGetBinderNames.WaitOne();
}
Но графический поток лочиться и тогда вапще ничего не делаеться, ну и по крайней мере ничего не перерисовываеться.
Можно вызывать у ProgressForm ShowDialog, и вызвать асинхронную операцию где нить в Shown у ProgressForm... но тогда логика начинает залазить в ProgressForm, что вапще как-то неправильно, может я чего-то не знаю, подскажите какие есть пути для потобной задачи.
Но хватать OnLoad главной формы даже в таком случае - не правильно.
Попробуй дописать пару строк Main метод класса Program:
Код:
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form progressForm = new ProgressbarForm();
progressForm.Show();
Application.Run(new MainForm());
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form progressForm = new ProgressbarForm();
progressForm.Show();
Application.Run(new MainForm());
}
Чтоб закрыть progressForm её можно передать как параметр в конструктор MainForm.
Видать никто не понимает меня в последнее время
[QUOTE="hardcase"]
А чем плохо показать splash-screen? С надписью вроде "идут загрузки".
[/QUOTE]
Вот его-то я и пытаюсь сделать. Хочу найти хороший подход к его решению.
[QUOTE="hardcase"]
Но хватать OnLoad главной формы даже в таком случае - не правильно.[/QUOTE]
Не могли бы вы пояснить почему это неправильно. Ведь куда лучше создать/показать объект и уничтожить/закрыть в одном месте чем если бы это делалось в раных местах.
Но проблема совершенно в другом. Ведь даже в случае, который предложили, ничего не поменялось, а именно если в OnLoad главной формы запускать синхронную операцию, то блокируеться графический поток и формы не перерисовываються, в общем приложение "висит". Если запускать асинхронно, то OnLoad завершит свою работу и откроеться главная форма ещё до закрытия сплаш-скрина. Так вот - что я придумал:
- У меня есть метод работающий асинхронно, который принимает два делегата ( обновления прогресса с сообщения ми что происходит и завершением операции) , которые он передаст BackGroundWorker'у и который запустит корректно в графическом потоке.
- Специальный ProgressForm который в конструкторе принимает делегат MethodInvoker и просто в своём OnShown запускает его.
Имея такую набор можно сделать следующее:
Код:
private void MainForm_Load(object sender, EventArgs e)
{
progressForm = new ProgressForm(
new MethodInvoker(delegate()
{
AInitClass.InitAsyncMethod(
// Делегат обновления прогресса (см. прототип в BackGroundWorker)
delegate(object progressChangedSender, ProgressChangedEventArgs progressChangedE)
{
progressForm.CommonInfo = progressChangedE.UserState.ToString();
},
// Делегат завершения прогресса (см. прототип в BackGroundWorker)
delegate(object runWorkerCompletedSender, RunWorkerCompletedEventArgs runWorkerCompletedE)
{
progressForm.Close();
}
);
}));
// Делаеться ShowDialog() то есть метод MainForm_Load не завершиться пока
// не закроеться progressFrom
progressForm.ShowDialog();
}
{
progressForm = new ProgressForm(
new MethodInvoker(delegate()
{
AInitClass.InitAsyncMethod(
// Делегат обновления прогресса (см. прототип в BackGroundWorker)
delegate(object progressChangedSender, ProgressChangedEventArgs progressChangedE)
{
progressForm.CommonInfo = progressChangedE.UserState.ToString();
},
// Делегат завершения прогресса (см. прототип в BackGroundWorker)
delegate(object runWorkerCompletedSender, RunWorkerCompletedEventArgs runWorkerCompletedE)
{
progressForm.Close();
}
);
}));
// Делаеться ShowDialog() то есть метод MainForm_Load не завершиться пока
// не закроеться progressFrom
progressForm.ShowDialog();
}
Таким образом чего мы добились:
- Методы по обраоботке результатов асихронной работы оформлены в виде анонимных функций и имеют доступ ко всем переменным OnLoad, которые она потом может использовать для завершения именициализации), что намой взгляд очень естственно
- Вся процедура инициализации сосредоточена в одном месте (чего я и хотел), как если бы она была синхронной ( то есть метод OnLoad не завершиться пока не будет выполнена инициализация и в тоже время не лочит приложения, что создалобы эфект неприязни и пользователя (вспомните как грузился фотошоп на вашем старом компьютере =) ) )
- Все это работает без длинных верениц методов, граничных классов, что являеться плюсом при изменении процедуры инициализации.
Спасибо за внимание
Нужно хоть как-нибудь, например выводить число в процентах.
Цитата: galileopro
Ребята а как в консоли отображать прогресс выполнения?
Нужно хоть как-нибудь, например выводить число в процентах.
Нужно хоть как-нибудь, например выводить число в процентах.
Я в таких случаях обычно спрашиваю:
[quote=hardcase]
Думать пробовали?
[/quote]
Код:
for (int i = 0; i < 100; ++i) {
Thread.Sleep(100);
Console.CursorLeft = 0;
Console.Write("Progress: " + i + "%");
}
Thread.Sleep(100);
Console.CursorLeft = 0;
Console.Write("Progress: " + i + "%");
}
hardcase предложил почти идеальное решение:
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form progressForm = new ProgressbarForm();
progressForm.Show();
Application.Run(new MainForm());
}
но можно поступить ещё проще, если вызывать форму с прогресс-баром в модальном режиме:
progressForm.ShowDialog();
тогда не надо передавать ссылку на неё в главную форму и там закрывать. Форма с прогресс-баром сама закроется, когда выполнит все необходимые действия и дальше откроется основная форма.