Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Прогресс бары и выполнение операций в фоне при старте приложения/формы

723
14 апреля 2007 года
Tommy
78 / / 13.10.2002
Здравствуйте.

Наверняка у всех возникала необходимость выполнения действий требующих времени. (всяких операций ввода-вывода, обращения к бд) и чтоб при этом форма не повисало и отображала какой-нить прогрес бар.
В случае когда это надо сделать по нажатию какой-нить кнопки - всё понятно, используем BackGroundWorker, или потоки и Control.Invoke().
Так вот, предположим это действие надо выполнить при запуске главной формы: перед тем как она нарисуеться вывести окошко с прогрес баром.
Делаю так:
 
Код:
private void MainForm_Load(object sender, EventArgs e)
{
    ProgressForm progressForm = new ProgressForm();
    progressForm.Show();

    BgWorker.RunWorkerAsync();

}

В этом случае метод завершиться и тогда форма нарисуеться заурыв форму с прогессом. Можно конечно её закрыть в 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 ShowDialog, и вызвать асинхронную операцию где нить в Shown у ProgressForm... но тогда логика начинает залазить в ProgressForm, что вапще как-то неправильно, может я чего-то не знаю, подскажите какие есть пути для потобной задачи.
5
16 апреля 2007 года
hardcase
4.5K / / 09.08.2005
А чем плохо показать splash-screen? С надписью вроде "идут загрузки".

Но хватать OnLoad главной формы даже в таком случае - не правильно.
Попробуй дописать пару строк Main метод класса Program:
 
Код:
static void Main() {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Form progressForm = new ProgressbarForm();
    progressForm.Show();
    Application.Run(new MainForm());
}

Чтоб закрыть progressForm её можно передать как параметр в конструктор MainForm.
723
24 апреля 2007 года
Tommy
78 / / 13.10.2002
Прошу прощёния за долгое отсутствие. Придумал решение и забыл про тему.

Видать никто не понимает меня в последнее время
[QUOTE="hardcase"]
А чем плохо показать splash-screen? С надписью вроде "идут загрузки".
[/QUOTE]
Вот его-то я и пытаюсь сделать. Хочу найти хороший подход к его решению.

[QUOTE="hardcase"]
Но хватать OnLoad главной формы даже в таком случае - не правильно.[/QUOTE]
Не могли бы вы пояснить почему это неправильно. Ведь куда лучше создать/показать объект и уничтожить/закрыть в одном месте чем если бы это делалось в раных местах.

Но проблема совершенно в другом. Ведь даже в случае, который предложили, ничего не поменялось, а именно если в OnLoad главной формы запускать синхронную операцию, то блокируеться графический поток и формы не перерисовываються, в общем приложение "висит". Если запускать асинхронно, то OnLoad завершит свою работу и откроеться главная форма ещё до закрытия сплаш-скрина. Так вот - что я придумал:
  1. У меня есть метод работающий асинхронно, который принимает два делегата ( обновления прогресса с сообщения ми что происходит и завершением операции) , которые он передаст BackGroundWorker'у и который запустит корректно в графическом потоке.
  2. Специальный 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();
}


Таким образом чего мы добились:
  1. Методы по обраоботке результатов асихронной работы оформлены в виде анонимных функций и имеют доступ ко всем переменным OnLoad, которые она потом может использовать для завершения именициализации), что намой взгляд очень естственно
  2. Вся процедура инициализации сосредоточена в одном месте (чего я и хотел), как если бы она была синхронной ( то есть метод OnLoad не завершиться пока не будет выполнена инициализация и в тоже время не лочит приложения, что создалобы эфект неприязни и пользователя (вспомните как грузился фотошоп на вашем старом компьютере =) ) )
  3. Все это работает без длинных верениц методов, граничных классов, что являеться плюсом при изменении процедуры инициализации.

Спасибо за внимание
49K
09 мая 2009 года
galileopro
1 / / 15.04.2009
Ребята а как в консоли отображать прогресс выполнения?
Нужно хоть как-нибудь, например выводить число в процентах.
5
09 мая 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: galileopro
Ребята а как в консоли отображать прогресс выполнения?
Нужно хоть как-нибудь, например выводить число в процентах.


Я в таких случаях обычно спрашиваю:
[quote=hardcase]
Думать пробовали?
[/quote]

 
Код:
for (int i = 0; i < 100; ++i) {
    Thread.Sleep(100);
    Console.CursorLeft = 0;
    Console.Write("Progress: " + i + "%");
}
297
02 июля 2009 года
koodeer
1.2K / / 02.05.2009
Автор темы появлялся в ней более двух лет назад, но мне всё же хочется внести свою лепту. Что-то уж больно сложное решение он предлагает.
hardcase предложил почти идеальное решение:
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form progressForm = new ProgressbarForm();
progressForm.Show();
Application.Run(new MainForm());
}
но можно поступить ещё проще, если вызывать форму с прогресс-баром в модальном режиме:
progressForm.ShowDialog();
тогда не надо передавать ссылку на неё в главную форму и там закрывать. Форма с прогресс-баром сама закроется, когда выполнит все необходимые действия и дальше откроется основная форма.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог