Подтвердить что ты не робот

Индикатор выполнения Winforms не обновляется (С#)

В моей программе [С# + winforms]. У меня есть индикатор выполнения и список.

С помощью одного метода я выполняю некоторые операции, а затем обновляю данные в Listview. Нет добавленных записей - это значение, которое я устанавливаю для свойства ProgressBar.value. То, что я хочу здесь, заключается в том, что по значению индикатора прогресса он должен показать свой прогресс. Однако индикатор выполнения не обновляется. Только в конце строки выполнения выполнения программы отображается весь прогресс, т.е. 100%

Может ли кто-нибудь помочь мне в этом отношении?

Спасибо, Amit

4b9b3361

Ответ 1

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

Хакерный ответ заключается в том, чтобы ввести Application.DoEvents() в ваш код, но это рискованно и имеет проблемы с повторным подключением и т.д.; и это просто немного хаки.

Лучшим вариантом может быть обработка на BackgroundWorker, периодическое переключение на поток пользовательского интерфейса для обновления вещей (Control.Invoke) - но это может быть сложно, если вы добавляете множество элементов в ListView.

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

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

class MyForm : Form
{
    BackgroundWorker worker;
    ListView list;
    Button btn;
    ProgressBar bar;
    public MyForm()
    {
        Text = "Loader";
        worker = new BackgroundWorker();
        worker.WorkerReportsProgress = true;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        list = new ListView();
        list.Dock = DockStyle.Fill;
        Controls.Add(list);
        btn = new Button();
        btn.Text = "Load";
        btn.Dock = DockStyle.Bottom;
        Controls.Add(btn);
        btn.Click += btn_Click;
        bar = new ProgressBar();
        bar.Dock = DockStyle.Top;
        Controls.Add(bar);
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        btn.Enabled = true;
    }

    void btn_Click(object sender, EventArgs e)
    {
        worker.RunWorkerAsync();
        btn.Enabled = false;
    }


    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < 100; i++)
        {
            string newRow = "Row " + i.ToString();
            worker.ReportProgress(i, newRow);
            Thread.Sleep(100);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        list.Items.Add((string)e.UserState);
        bar.Value = e.ProgressPercentage;
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

Ответ 2

Действительно извините друзей,

На самом деле, я оценил значение для поля ProgressBar.value, но не использовал метод update(). Я использовал это, и моя проблема была решена.

Спасибо всем за ваши ответы

Ответ 3

Как сказал Марк, вы хотите убедиться, что вы откручиваете новый поток, чтобы выполнить долгое вычисление. Таким образом, поток пользовательского интерфейса (который должен делать все обновления экрана) может перерисовывать панель progres всякий раз, когда вы изменяете процент завершения.

Важно отметить, что только поток пользовательского интерфейса может обновлять интерфейс. Итак, как только вы работаете в отдельном потоке, вам нужно пройти дополнительный обруч, чтобы убедиться, что изменение пользовательского интерфейса обрабатывается в потоке пользовательского интерфейса. Если вы не уверены, какой поток вы используете, вы можете проверить значение InvokeRequired (если ваш класс является System.Windows.Form), чтобы узнать, действительно ли вы в потоке пользовательского интерфейса.

Чтобы обработать вашу команду в потоке пользовательского интерфейса, используйте функцию Control.Invoke(), чтобы убедиться, что обновление обрабатывается в потоке пользовательского интерфейса для элемента управления, с которым вы работаете.

В моем примере кода ниже я создаю тип функции делегата и заранее объявляю активированную функцию. Я не делал этого с помощью каких-либо классных функций С# 3.5, но я уверен, вы могли бы lamba, чтобы сделать то же самое.

 private void bCreateInvoices_Click(object sender, EventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(CreateInvoices);
        worker.RunWorkerAsync(this);
    }

 // Here is the long running function that needs to update the progress bar
 public void CreateInvoices(object sernder, DoWorkEventArgs e)
    {
        int totalChecked = CountCheckedServiceOrders();
        int totalCompleted = 0;

        foreach (...data to process...) {
            totalCompleted++;
            if (InvokeRequired) {
               Invoke(new Change(OnChange), "status text", 
                        totalCompleted, totalChecked);                
            }
        }
    }

    // this code updates the status while a background thread works
    private delegate void Change(string status, int complete, int total);
    private void OnChange(string status, int complete, int total)
    {
        if (status == null) {
            progressBar.Visible = false;
            lStatus.Text = "Task complete";
            progressBar.Value = 0;
        } else {
            progressBar.Visible = true;
            progressBar.Minimum = 0;
            progressBar.Maximum = total;
            progressBar.Value = complete;
            lStatus.Text = status;
        }

    }

Посмотрите MSDN Control.InvokeRequired справочная страница и Страница MSDN Control.Invoke для получения дополнительной информации.

Ответ 4

Значение ProgressBar.Value должно быть от 0 до 100.

Я предполагаю, что ваша проблема в том, что вы обновляете ListView в потоке графического интерфейса. Это означает, что вам нужно вызвать Application.DoEvents() после изменения свойства ProgressBar.Value.

Лучше всего запустить BackgroundWorker и использовать событие ProgressChanged для обработки обновления ProgressBar.

Вот еще один вопрос по той же теме.