Winforms: Как отобразить «загрузочную» форму? - PullRequest
4 голосов
/ 07 мая 2010

У меня есть сетка, и при двойном щелчке строки загружается форма. Однако необходимо загрузить много данных, поэтому я хотел бы отобразить простую форму с текстом «загрузка, пожалуйста, подождите ...». И когда вся загрузка закончится, форма должна исчезнуть.

Это то, что у меня есть сейчас, но оно не работает:

Код, который вызывает форму с большим количеством данных:

FormWithLotData form = new FormWithLotData();
form.ShowDialog(this);

Конструктор FormWithLotData:

// Show load form
FormIsLoading frm = new FormIsLoading();
_CloseLoadForm closeForm = new _CloseLoadForm(frm.Close);
System.Threading.Thread thread = new System.Threading.Thread(frm.Show);

thread.Start();

InitializeComponent();

this.Visible = false;

LoadAllData();

this.Visible = true;

// Close load form
Invoke(closeForm);

Надеюсь, вы поможете мне.

EDIT: Я хотел бы показать анимированный GIF в форме загрузки.

РЕШЕНИЕ: Я создал фоновый рабочий. Событие DoWork обрабатывает всю загрузку, и с помощью метода invoke () я добавляю узлы в древовидную структуру. Теперь графический интерфейс не зависает, и у пользователя нет идеи, что приложение зависает.

Ответы [ 5 ]

6 голосов
/ 07 мая 2010

Вам необходимо поменять код.

Конструктор FormWithLotData работает в потоке пользовательского интерфейса. Это поток, который должен показать вашу форму FormIsLoading. Поэтому вместо того, чтобы пытаться отобразить эту форму с помощью нового потока, загрузите данные вместе с ним.

Способ DoEvents, предложенный другими, является самым простым в реализации и (возможно? Сам никогда не делал) может работать хорошо.

Лучше использовать шаблон для загрузки данных в рабочий поток. Прежде чем показывать свои FormWithLotData, начните загрузку данных в фоновом потоке и покажите диалоговое окно загрузки. Метод, который загружает данные, должен иметь метод обратного вызова в диалоге загрузки, чтобы сигнализировать, когда он должен закрыть (). После его закрытия вы можете создать новый FWLD, передать ему уже загруженные данные и показать его.

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


После вашего обновления кажется, что DoEvents будет единственным реальным ответом на ваш вопрос, но с некоторыми оговорками.

Вы не сможете показывать другую форму МОДАЛЬНО, пока создаете свое дерево. Вам все равно придется выполнять тяжелую работу в конструкторе формы. Вам все равно придется скрыть свою основную форму и Show () (не ShowDialog) форму загрузки. Вы также должны будете вызывать DoEvents в каждый возможный момент при построении вашего дерева. Это не совсем элегантное решение, но, вероятно, будет лучшим выбором на данный момент.

5 голосов
/ 07 мая 2010

как насчет ...

FormIsLoading frm = new FormIsLoading();
frm.Show();
Application.DoEvents();

// ... load data ...

frm.Close();
2 голосов
/ 07 мая 2010

В событие Form_Load добавьте следующее:

this.Visible = true;
Application.DoEvents();

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

0 голосов
/ 19 июля 2017
  1. Внутри формы вы можете использовать элемент управления Timer для имитации загрузки используя ProgressBar, когда он достигает 100, он выгружает форму или любой вид анимации.

    для кода прогресса просто добавьте элемент управления из панели инструментов, а затем напишите следующий код:

ProgressBar1.Value = ProgressBar1.Value+1;
if(ProgressBar1.Value == 100)
{ 
  timer1.Enabled = false; this.Hide();
  MessageBox.Show("Complete Loading...");
}
0 голосов
/ 07 мая 2010

Не делайте LoadAllData() непосредственно в потоке пользовательского интерфейса, вместо этого запустите фоновый поток, чтобы сделать это. В вашем обработчике события Form_Loaded используйте AutoResetEvent и дождитесь, пока он не будет сигнализирован потоком извлечения фоновых данных. Получив сигнал, вы можете продолжать делать с данными все, что вам нужно, например связать их с пользовательским интерфейсом.

Этот метод все еще немного неуклюж по разным причинам, но он поможет вам начать работу.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...