Могу ли я приостановить перерисовку формы до тех пор, пока не выполню все обновления?

StackOverflow https://stackoverflow.com/questions/615781

Вопрос

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

Я меняю цвет задней панели с Lime на default Я меняю FormBorderStyle на FixedSingle Я меняю клавишу TransparencyKey на Color.None

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

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

G

Это было полезно?

Решение

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

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

Объяснение того, что делает приведенный ниже код:

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

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

В НОВОЕ пример:

    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);
        }
    }

Другие советы

Попробуйте использовать форму.Свойство с двойной буферизацией.Установите для него значение "true".

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

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

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

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

Например:

  this.Opacity = 0;
  this.BackColor = Color.FromKnownColor(KnownColor.Control);
  this.FormBorderStyle = FormBorderStyle.Sizable;
  this.TransparencyKey = Color.Empty;
  this.Opacity = 1;

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

ПРЕДУПРЕЖДЕНИЕ:Я не пропагандирую использование этого метода, но вы можете попробовать его, если действительно хотите.Это помогало мне в прошлом.

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);
 }

Способ отправить все "изображение" формы на экран за один шаг - это включить двойной буфер.

В конструкторе вы можете задать стили управления

VB.NET:

SetStyle(ControlStyles.DoubleBuffer, True)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top