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

Почему не будет контролировать обновление/обновление в середине процесса

У меня есть форма Windows (С#.NET) с statusLabel, которую я, похоже, не могу обновить в середине процесса в методах обработчика событий. Мой код выглядит так...

    void Process_Completed(object sender, EventArgs e)
    {

        string t = "Process is finished!";
        this.Invoke(new StatusLabelUpdator(updateStatusLabel), new object[] { t });
    }

    void Process_Started(object sender, EventArgs e)
    {
        string t = "Process has begun";
        this.Invoke(new StatusLabelUpdator(updateStatusLabel), new object[] { t });
    }

    private delegate void StatusLabelUpdator(string text);
    private void updateStatusLabel(string text)
    {
        StatusLabel1.Text = text;
        statusStrip1.Invalidate();
        statusStrip1.Refresh();
        statusStrip1.Update();
    }

Когда я запускаю код, как только процесс запускается, запускается метод Process_Started, а через пару секунд запускается метод Process_Completed. По какой-то причине я не могу заставить ярлык статуса отображаться "Процесс начался". Он только когда-либо показывает: "Процесс закончен!". Как вы можете видеть, я попытался сделать недействительным, обновив и обновив полосу статуса, которая содержит метку состояния, но не имеет успеха. Я не могу вызывать update/refresh/invalidate на самой статусной метке, потому что эти методы недоступны для нее. Что я делаю неправильно?

ДОБАВЛЕННАЯ ИНФОРМАЦИЯ:

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

public void DoSomeProcess()
{
    TriggerProcessStarted();
    System.Threading.Thread.Sleep(2000);   // For testing..
    TriggerProcessComplete();
}

и внутри методов TriggerProcessxxxx я запускаю события, используя этот код...

var EventListeners = EH.GetInvocationList();    //EH is the appropriate EventHandler
if (EventListeners != null)
{
    for (int index = 0; index < EventListeners.Count(); index++)
    {
        var methodToInvoke = (EventHandler)EventListeners[index];
        methodToInvoke.BeginInvoke(this, EventArgs.Empty, EndAsyncEvent, new object[] { });
    }
}

Наконец, я добавил Application.DoEvents() в метод updateStatusLabel, но это не помогло. Я все равно получаю тот же результат. Вот мой метод обновления.

private void updateStatusLabel(string text)
{
    StatusLabel1.Text = text;
    statusStrip1.Refresh();
    Application.DoEvents(); 
}

Итак, я думаю, что "обработка" происходит в потоке пользовательского интерфейса, но обработчик событий вызывается в его собственном потоке, который затем вызывает обновление управления обратно в потоке пользовательского интерфейса. Это глупый способ делать вещи? Примечание. Класс, содержащий метод DoSomeProcess(), находится в отдельной библиотеке .NET ClassLibrary, на которую я ссылаюсь.

4b9b3361

Ответ 1

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

Ответ должен состоять в длительной обработке в отдельном потоке. Хак (IMHO) должен использовать Application.DoEvents, чтобы поток пользовательского интерфейса выполнял некоторые элементы интерфейса во время обработки. Если вы поместите один из них после обновления ярлыка и до того, как начнете обработку, шансы довольно высоки, ярлык будет перекрашен. Но тогда во время обработки никакие дополнительные события рисования не могут быть обработаны (приводят к полуоткрытым окнам, когда кто-то перемещает другое окно приложения поверх вашего приложения и обратно и т.д.). Следовательно, я называю это взломом (хотя, э-э, эм, мне известно это сделать:-)).

Изменить Обновление на основе ваших изменений:

Re

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

Я предполагаю, что DoSomeProcess запускается из потока пользовательского интерфейса (например, в прямой реакции на нажатие кнопки или подобное). Если да, то да, ваша обработка определенно находится в потоке пользовательского интерфейса. Поскольку TriggerProcessStarted асинхронно запускает обратный вызов через BeginInvoke, вы не знаете, когда он будет работать, но в любом случае ваш код сразу же запускается в обработку, никогда не уступая, поэтому никто другой не сможет захватить этот поток, Поскольку этот поток пользовательского интерфейса, вызов делегата будет блокировать вызов Invoke для вызова текста ярлыка, после чего ему придется ждать потока пользовательского интерфейса (который занят обработкой). (И если предположить, что он запланирован на другой поток, я не мог бы на 100% убедить себя в любом случае, потому что у Microsoft есть два разных BeginInvoke - которые IIRC, один из дизайнеров, признал, был Really Dumb Idea - и это было в то время как я боролся с этим материалом.)

Если вы делаете вызовы TriggerProcessStarted для ваших обратных вызовов синхронными, вы должны быть в порядке. Но в идеале планируйте обработку (если она не делает UI) в своем собственном потоке.