Не обновляет GUI вовремя

У меня есть класс, который обновляет элемент GUI

public class UpdateLabelClass
{
    static MainGUI theForm = (MainGUI)Application.OpenForms[0];
    Label lblCurProgress = theForm.curProgress;

    public ProgressBarUpdate()
    {

    }
    public void UpdateLabel(String newLabel)
    {
        lblCurProgress.Text = newLabel;
    }
}

А в других классах я делаю экземпляр класса и вызываю UpdateLabel (someString);

Теперь проблема в том, что он пропускает операцию обновления метки, поэтому я подумал:Может быть, это неТ даже не до кода "поэтому я поместил MessageBox.Show () сразу после него, и он обновил метку.

Каковы возможные причины пропустить обновление метки, но выполнить это, когда я сразу же добавлю сообщение? Программа собирается быстро?

 jAC17 мая 2013 г., 15:03
@NipunAmbastha: я неЯ думаю, если бы это было так,UpdateLabel()-Метод бросил быCrossThreadMessagingException потому что там'с нет;Invoke()
 ja7217 мая 2013 г., 16:06
Может бытьUpdateLabelClass должны запускать события, когда достигнут прогресс, и форма подписывается на эти события.
 Nipun Ambastha17 мая 2013 г., 14:59
Это в другой теме.

Ответы на вопрос(2)

Решение Вопроса

вы неправильно выполняете длинную операцию в основном потоке пользовательского интерфейса, которая не позволяет обновить метку. Вы могли бы "исправить» это путем вызова DoEvents ():

public void UpdateLabel(String newLabel)
{
    lblCurProgress.Text = newLabel;
    Application.DoEvents();
}

Но это просто лейкопластырь поверх плохого дизайна.Вы должны правильно переместить этот код в фоновый поток и использовать делегат / Invoke () для обновления метки.

Редактировать: (отвечая на дополнительный вопрос)

По умолчанию ваше приложение выполняется в одном потоке. Это включает в себя код, который вы добавляете для управления событиями, а также код, который вы можете 'не вижу, что это работает за кулисами, чтобы заставить ваше приложение реагировать так, как выбуду ожидать. Такие вещи, как взаимодействие с пользователем (щелчки мыши, нажатия клавиш и т. Д.) И сообщения рисования (когда элементы управления изменены, ваше окно скрыто) помещаются в очередь. Эти ожидающие сообщения в очереди обрабатываются только после прекращения работы вашего кода. Если у вас выполняется длинный кусок кода, например длинный цикл, тогда эти сообщения просто находятся в очереди, ожидая обработки. Таким образом, обновление до метки нене происходит до тех пор, пока не закончится ваш цикл. То, что делает DoEvents (), говорит приложению обработать эти ожидающие сообщения в очереди прямо сейчас, а затем вернуться к коду, который выполнялся в данный момент. Это позволяет обновлять ярлык в режиме реального времени так, как вы этого ожидаете.

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

Правильное решение - переместить этот длинный код в другой поток, что позволит основному потоку пользовательского интерфейса реагировать и обновляться. Для многих сценариев самый простой подход - этоBackgroundWorker () контролировать форму и подключить события DoWork (), ProgressChanged () и RunWorkerCompleted (). * Однако для обработки события ProgressChanged () необходимо установить для свойства WorkerReportsProgress () значение true. Последние два события уже маршалированы для основного потока пользовательского интерфейса для вас, поэтому вы неНе нужно беспокоиться об исключениях между потоками. Из обработчика DoWork () вы вызываете ReportProgress () и передаете процентное значение прогресса и необязательный другой объект (это может быть что угодно). Эти значения могут быть получены в событии ProgressChanged () и использованы для обновления графического интерфейса. Событие RunWorkerCompleted () возникает, когда вся работа в обработчике DoWork () завершена.

В твоем случае тыУ нас есть отдельный класс, который делает работу. Вы можете отразить то, что делает BackgroundWorker, вручную создав собственный поток в этом классе для выполнения этой работы. Если вы хотите обновить прогресс, сделайте так, чтобы ваш класс поднялCustom Event что основная форма подписывается на. Однако, когда это событие получено, оно будет запущено в контексте отдельного потока. Тогда необходимопредводитель» вызов через границы потока, чтобы код выполнялся в основном потоке пользовательского интерфейса перед обновлением элементов управления. Это достигается с помощью делегатов ("указатели» в методы) и метод Invoke (). * Есть и другие методы для выполнения этой задачи, такие как SynchronizationContext.

УвидетьВот для некоторых примеров этих подходов.

Наконец, вот очень простой пример класса, который вызывает пользовательские события из отдельного потока:

public partial class Form1 : Form
{

    private Clock Clk;

    public Form1()
    {
        InitializeComponent();

        Clk = new Clock();
        Clk.CurrentTime += new Clock.TimeHack(Clk_CurrentTime);
    }

    private void Clk_CurrentTime(string hack)
    {
        if (label1.InvokeRequired)
        {
            Clock.TimeHack t = new Clock.TimeHack(Clk_CurrentTime);
            label1.Invoke(t, new object[] { hack });
        }
        else
        {
            label1.Text = hack;
        }
    }

}

public class Clock
{
    public delegate void TimeHack(string hack);
    public event TimeHack CurrentTime;

    private Thread t;
    private bool stopThread = false;

    public Clock()
    {
        t = new Thread(new ThreadStart(ThreadLoop));
        t.IsBackground = true; // allow it to be shutdown automatically when the application exits
        t.Start();
    }

    private void ThreadLoop()
    {
        while (!stopThread)
        {
            if (CurrentTime != null)
            {
                CurrentTime(DateTime.Now.ToString());
            }
            System.Threading.Thread.Sleep(1000);
        }
    }

    public void Stop()
    {
        stopThread = true;
    }

}
 Idle_Mind17 мая 2013 г., 18:07
Смотрите отредактированный ответ выше ...
 Alexey17 мая 2013 г., 15:18
Это решение сработало. Но можете ли вы объяснить, почему?
public void UpdateLabel(String newLabel)
{
   lblCurProgress.Text = newLabel;
   lblCurProgress.Refresh();
}
 PLED17 мая 2013 г., 15:21
Меня интересует, что может сказать @Idle_Mind.
 Alexey17 мая 2013 г., 15:16
Безразлично»обновить. Как я указал, по какой-то причине он обновляется только тогда, когда я вызываю MessageBox.Show () сразу после вызова.
 PLED17 мая 2013 г., 15:15
Я использую метод, довольно близкий к описанному выше, на заставке для приложения с длительной загрузкой (около 13 секунд). Хорошо работает и дает пользователям обратную связь, чтобы они знали эточто-то делает.
 jAC17 мая 2013 г., 15:07
Я нене думаю, что обновление необходимо, но давайтесмотри.

Ваш ответ на вопрос