Форма не обновляется после ShowDialog (Compact Framework) - PullRequest
1 голос
/ 21 сентября 2010

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

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

Form loginDialog = new Form();
DialogResult result = loginDialog.ShowDialog();
loginDialog.Dispose();

//I've tried everything at this point to get the form to refresh before performing
//login tasks
this.Refresh();
this.Invalidate();
Application.DoEvents();


PerformHeavyLoginTasks();

Кто-нибудь знает, что может пойти не так? Спасибо

Ответы [ 2 ]

1 голос
/ 21 сентября 2010

Хорошо, я понял это. Проблема была с пользовательским элементом управления в фоновой форме, который вручную рисовал себя, используя прямоугольники и тому подобное. Я думаю, что это небольшая ошибка в фреймворке, так как я назвал Refresh и Invalidate для этого элемента управления, и он должен был перекраситься. Мне пришлось создать метод, который бы вызывал переопределение OnPaint элемента управления напрямую, поскольку Invalidate и Refreshed были в значительной степени проигнорированы.

0 голосов
/ 21 сентября 2010

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

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

По своей природе это довольно медленный процесс, поскольку пользовательский интерфейс не должен вытеснять важные вещи.

Если вы выполняете интенсивную обработку сразу после того, как это PostMessage происходит, обработка этих сообщений Windows часто может быть замедлена, в результате пользовательский интерфейс выглядит «заблокированным» или рисует очень медленно. Это усугубляется, если выполняемая вами обработка выполняется в том же потоке, что и пользовательский интерфейс.

Почему ваши усилия не улучшают ситуацию?

  • Вызов Refresh просто отправляет другое сообщение. Теперь это сообщение поступает в очередь на обработку, поэтому на самом деле все будет еще хуже.
  • Вызов Invalidate делает почти то же самое, что и Refresh, только асинхронно. Опять же, все ухудшается.
  • DoEvents указывает насосу сообщений выводить, переводить и отправлять сообщение. Эта диспетчеризация все еще должна быть обработана в потоке пользовательского интерфейса, так что это будет происходить до тех пор, пока поток не успеет выполнить работу (т.е. после вашей обработки)

Итак, как нам это "исправить"?

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

new Thread(PerformHeavyLoginTasks)
{
    IsBackground = true
}.Start();

Вы можете пойти еще дальше и дать интерфейсу «быстрый старт» при обработке (в данном примере 10 мс):

new Thread(new ThreadStart(delegate
    {
        Thread.Sleep(10);
        PerformHeavyLoginTasks();
    }))
{
    IsBackground = true
}.Start();

Конечно, это может означать, что теперь вам нужно асинхронно обрабатывать следующее «отображение», если отображаемый пользовательский интерфейс зависит от результата обработки. Существует множество онлайн-ресурсов по асинхронным шаблонам, поэтому я не буду бить эту мертвую лошадь здесь.

...