progressBar пока MainFrom инициализирует
У меня есть приложение windows form, которое должно загрузить кучу вещей перед загрузкой главного окна. Я думал, что это оправдает ProgressBar, поэтому я подумал, что я показываю другую форму, которая содержит ProgressBar Control используя конструктор моей основной формы.
Все это прекрасно работает, но если я попытаюсь поместить текст в Label на вводной форме, его содержание не будет отображаться, пока не будет загружена основная форма. Есть ли способ избежать этого, кроме как сначала загрузить окно ввода?
4 ответов:
Вы можете показать свою SplashForm либо из основной программы, либо из конструктора MainForm, что на самом деле не имеет значения. Вы видите, что до тех пор, пока ваш процесс загрузки не завершен, никакие сообщения не обрабатываются и, следовательно, никаких обновлений экрана не происходит. ProgressBar является исключением, он запускает свой собственный поток именно по этой причине.
Короткое решение состоит в том, чтобы сделать
SplashForm.Update()после изменения метки. Немного более сложным было бы начать отдельный поток с MessagePump (Приложение.Бежать). Вот такой вопрос с еще несколькими наводками.
предупреждение: этот пост содержит элементы саморекламы; o)
Я бы, вероятно, использовал форму всплеска в этом случае. Я написал сообщение в блоге некоторое время назад (вызванное этим так называемым Q&A) О потокобезопасной форме всплеска, которая может использоваться вместе с длительными инициализациями основной формы.
Короче говоря, подход заключается в использовании ShowDialog, но для создания и отображения формы в отдельном потоке, чтобы она не блокировала основной поток. Форма содержит статус метка сообщения (конечно, может быть расширена с помощью progressbar). Затем есть статический класс, который предоставляет потокобезопасные методы для отображения, обновления и закрытия формы splash.Сжатые примеры кода (для комментируемых примеров кода проверьте сообщение в блоге):
using System; using System.Windows.Forms; public interface ISplashForm { IAsyncResult BeginInvoke(Delegate method); DialogResult ShowDialog(); void Close(); void SetStatusText(string text); } using System.Windows.Forms; public partial class SplashForm : Form, ISplashForm { public SplashForm() { InitializeComponent(); } public void SetStatusText(string text) { _statusText.Text = text; } } using System; using System.Windows.Forms; using System.Threading; public static class SplashUtility<T> where T : ISplashForm { private static T _splash = default(T); public static void Show() { ThreadPool.QueueUserWorkItem((WaitCallback)delegate { _splash = Activator.CreateInstance<T>(); _splash.ShowDialog(); }); } public static void Close() { if (_splash != null) { _splash.BeginInvoke((MethodInvoker)delegate { _splash.Close(); }); } } public static void SetStatusText(string text) { if (_splash != null) { _splash.BeginInvoke((MethodInvoker)delegate { _splash.SetStatusText(text); }); } } }Пример использования:
SplashUtility<SplashForm>.Show(); SplashUtility<SplashForm>.SetStatusText("Working really hard..."); SplashUtility<SplashForm>.Close();
Там точно есть. Это называется
BackgroundWorker.Вот фрагмент кода из Figo Fei с небольшой модификацией для объяснения:
private void button1_Click(object sender, EventArgs e) { progressBar1.Maximum = 100; backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged); backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // This would be the load process, where you put your Load methods into. // You would report progress as something loads. for (int i = 0; i < 100; i++) { Thread.Sleep(100); backgroundWorker1.ReportProgress(i); //run in back thread } } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) //call back method { progressBar1.Value = e.ProgressPercentage; } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) //call back method { progressBar1.Value = progressBar1.Maximum; }Надеюсь, это поможет вам.
Проблема, скорее всего, заключается в том, что в то время, когда вы пытаетесь отобразить форму индикатора выполнения, не выполняется цикл сообщений. В точке входа вашего приложения должна быть строка кода, которая выглядит примерно следующим образом.
Application.Run(new Form1());Вызов приложения.Run запустит цикл сообщений, но видите ли вы, как конструктор Form1 выполняется до запуска цикла сообщений? И поскольку ваша логика индикатора выполнения находится в этом конструкторе, то нет работает механизм, который может отправлять сообщения рисования формы.
Я думаю, что лучший подход-это сначала загрузить заставку и запустить рабочий поток (для этого можно использовать BackgroundWorker), который выполняет трудоемкую работу. Индикатор выполнения будет жить на форме заставки, и вы будете периодически обновлять его. После завершения работы вы можете закрыть заставку и загрузить основную форму.
Comments