Могу ли я приостановить перерисовку формы, пока не выполню все обновления? - PullRequest
7 голосов
/ 05 марта 2009

Используя C # и .Net 2.0, я использую форму неправильной формы (TransparencyKey, FormBorderStyle = None и т. Д.) И хочу разрешить «нормальный» граничный режим.

Я изменяю цвет спины на Lime по умолчанию Я изменяю FormBorderStyle на FixedSingle Я изменяю прозрачность на Colour.None

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

Я думаю, это вызвано тем, что форма перерисовывается после каждой строки кода, возможно ли приостановить рисование формы до тех пор, пока я не внесу свои изменения, а затем просто перерисовать форму один раз?

G

Ответы [ 5 ]

8 голосов
/ 05 марта 2009

НОВЫЙ ответ: Переопределите WndProc и заблокируйте сообщение WM_PAINT, пока вы применяете новые свойства окна.

СТАРЫЙ ответ: Переопределите WndProc и заблокируйте сообщение WM_ERASEBKGND.

Объяснение того, что делает код ниже:

Когда область окна становится недействительной, Windows отправляет в элемент управления серию сообщений, в результате которых появляется недавно нарисованный виджет. Раннее сообщение в этой серии - WM_ERASEBKGND. Обычно, в ответ на это сообщение, элемент управления окрашивает себя в сплошной цвет. Позже, в ответ на сообщение WM_PAINT (которое обычно используется нами в событии OnPaint), фактическое рисование выполняется. Если этот рисунок нетривиален, перед обновлением виджета будет задержка, и вы получите раздражающее мерцание.

Глядя на ваш код снова, я явно решал другую проблему. Попробуйте этот новый пример. Он заблокирует рисование формы / элемента управления, если флаг bAllowPaint не установлен.

Пример NEW :

    private const int WM_PAINT = 0x000F;

    protected override void WndProc(ref Message m)
    {
        if ((m.Msg != WM_PAINT) ||
            (bAllowPaint && m.Msg == WM_PAINT))
        {
            base.WndProc(ref m);
        }
    }

Пример СТАРЫЙ :

    private const int WM_ERASEBKGND = 0x0014;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg != WM_ERASEBKGND) // ignore WM_ERASEBKGND
        {
            base.WndProc(ref m);
        }
    }
4 голосов
/ 06 марта 2009

Вы изменяете свойства, которые оказывают довольно большое влияние на форму. TransparencyKey и FormBorderStyle требуют изменения битов стиля окна. Windows не позволяет эти биты стиля быть изменены. Windows Forms реализует их, полностью разрушая окно и заново создавая его с нуля. Уловка, но это требует времени, и форма будет перекрашиваться каждый раз, когда вы меняете стиль. Вызывает неприятный визуальный эффект, который вы видите.

Попробуйте это: 1. Установите Opacity на 0, чтобы форма стала невидимой 2. Изменить BackColor, нет проблем 3. Измените FormBorderStyle, окно воссоздается 4. Измените TransparencyKey, окно будет воссоздано 5. Измените непрозрачность на 1, окно воссоздается, а затем становится видимым

Например:

  this.Opacity = 0;
  this.BackColor = Color.FromKnownColor(KnownColor.Control);
  this.FormBorderStyle = FormBorderStyle.Sizable;
  this.TransparencyKey = Color.Empty;
  this.Opacity = 1;
4 голосов
/ 05 марта 2009

Попробуйте свойство Form.DoubleBuffered. Установите для него значение «true».

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

Наконец, вызовите SuspendLayout до ваших изменений и ResumeLayout после. Имейте в виду, что это влияет только на размещение дочерних элементов управления. Если вы делаете какой-либо пользовательский рисунок, свойство DoubleBuffered даст вам больше отдачи.

3 голосов
/ 12 января 2010

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

ВНИМАНИЕ: я не пропагандирую использование этого метода, но вы можете попробовать его, если действительно хотите. Это помогло мне в прошлом.

Win32.LockWindowUpdate(this.Handle);
try
{
   //make your changes here
}
finally
{
  //release the lock
  Win32.LockWindowUpdate((IntPtr)0);
}

Этот код опирается на следующий вспомогательный код:

public class Win32
{
  private Win32() { }

    /// <summary>
    /// Lock ore relase the wndow for updating.
    /// </summary>
    [DllImport("user32")]
    public static extern int LockWindowUpdate(HWND hwnd);
 }
0 голосов
/ 05 марта 2009

Способ отправить все «образы» формы на экран за один шаг - включить DoubleBuffer.

В конструкторе вы можете установить ControlStyles

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)
...