progressBar при инициализации MainFrom - PullRequest
3 голосов
/ 24 августа 2009

У меня есть приложение Windows Form, которое должно загрузить несколько вещей перед загрузкой главного окна. Я подумал, что это оправдывает ProgressBar, поэтому я решил показать другую форму, содержащую ProgressBar Control, используя конструктор моей основной формы.

Все работает нормально, но если я попытаюсь поместить текст в Label в форме ввода, его содержимое не будет отображаться, пока не будет загружена основная форма. Есть ли способ избежать этого, кроме первой загрузки вступительного окна?

Ответы [ 4 ]

5 голосов
/ 24 августа 2009

Внимание: этот пост содержит элементы саморекламы; o)

Я бы, вероятно, использовал форму всплеска в этом случае. Некоторое время назад я написал сообщение в блоге (вызванное этим SO Q & A ) о поточно-ориентированной всплывающей форме, которая может использоваться вместе, и будет долго выполняться инициализация основной формы.

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

Примеры сжатого кода (для примеров с комментариями, проверьте сообщение в блоге):

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();
2 голосов
/ 24 августа 2009

Конечно, есть. Это называется BackgroundWorker.

Вот фрагмент кода из Фигу Фэй с небольшими изменениями для пояснения:

    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;
    }

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

1 голос
/ 24 августа 2009

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

Короткое решение - сделать SplashForm.Update() после изменения метки. Немного сложнее было бы запустить отдельный поток с помощью MessagePump (Application.Run). Вот ТАК вопрос с еще несколькими предложениями.

0 голосов
/ 24 августа 2009

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

Application.Run(new Form1());

Вызов Application.Run запустит цикл сообщений, но видите ли вы, как конструктор Form1 выполняется до запуска цикла сообщений? А поскольку ваша логика индикатора выполнения находится в этом конструкторе, то не работает механизм, который мог бы отправлять сообщения рисования формы.

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

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