Двойная буферизация в .NET Compact Framework

#c# #.net #windows-mobile #compact-framework #doublebuffered

#c# #.net #windows-mobile #compact-framework #двойная буферизация

Вопрос:

Мне было интересно, может ли кто-нибудь объяснить мне, как удвоить буфер полной формы в .net compact framework. Я нашел примеры двойной буферизации, но, похоже, ни один из них не работает.

Мы создали приложение с несколькими формами. Некоторые из этих форм требуют много времени для отображения на экране, что приводит к мерцанию. Чтобы дать вам некоторое представление о нашем приложении, я собираюсь объяснить одну из форм. Эта форма содержит пользовательский элемент управления, некоторые панели, текстовые поля и кнопки. В usercontrol есть панели, которые имеют пользовательский рисунок (рисование текста и изображений (с прозрачностью) на экране). И даже некоторые из этих панелей содержат другие панели, которые делают то же самое. Панели также имеют пользовательский рисунок, потому что мы рисуем текст на экране с некоторыми эффектами и т. Д. Для отрисовки каждой панели требуется время, что означает, что если у нас есть 9 панелей в сетке 3×3, они отрисовываются и отображаются в случайном порядке, а не отображаются все одновременно. То же самое происходит с текстовым рисунком и т. Д. Мы хотели бы, чтобы все в форме отображалось одновременно.

Итак, мой вопрос в том, могу ли я создать «супер» класс, который выполняет двойную буферизацию, выполняет рисование в памяти полной формы?

Могу ли я расширить свои формы currect из него без необходимости что-либо менять в своих элементах управления, панелях, рисовании изображений и т. Д.?

Спасибо

Комментарии:

1. Я знаю только двойную буферизацию для изображений, а не для элементов Windows, таких как кнопки, поля ввода и т.д. Вы можете хранить в памяти стопку форм, а затем быстро переключаться между ними. В MSDN есть пример.

Ответ №1:

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

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

     /// <summary>
/// Implements the functionality for a control that can be double buffered
/// </summary>
public class DoubleBufferableControl : ScrollableControl
{
    public event BufferedPaintEventHandler BufferedPaint;
    private bool doubleBuffered;
    private Bitmap backBuffer;
    private Size oldSize;

    /// <summary>
    /// Gets or sets whether this control will use double buffering
    /// </summary>
    public bool DoubleBuffered
    {
        get
        {
            return doubleBuffered;
        }
        set
        {
            if (value amp;amp; !doubleBuffered amp;amp; Width > 0 amp;amp; Height > 0)
            {
                backBuffer = new Bitmap(Width, Height);
            }
            else if(!value amp;amp; doubleBuffered)
            {
                backBuffer.Dispose();
                backBuffer = null;
            }

            doubleBuffered = value;
        }
    }

    /// <summary>
    /// Gets the off screen image used for double buffering
    /// </summary>
    public Bitmap BackBuffer
    {
        get
        {
            return backBuffer;
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="DoubleBufferableControl"/> class.
    /// </summary>
    public DoubleBufferableControl()
    {
        AutoScroll = false;
        doubleBuffered = DefaultDoubleBuffered;
        oldSize = Size;
    }

    #region Designer
    private bool DefaultDoubleBuffered = false;
    protected virtual bool ShouldSerializeDoubleBuffered()
    {
        return !this.doubleBuffered.Equals(DefaultDoubleBuffered);
    }
    protected void ResetDoubleBuffered()
    {
        DoubleBuffered = DefaultDoubleBuffered;
    }
    #endregion

    /// <summary>
    /// Raises the Paint event
    /// </summary>
    /// <param name="e">A PaintEventArgs that represents event data</param>
    protected override sealed void OnPaint(PaintEventArgs e)
    {
        if (doubleBuffered)
        {
            DoubleBufferedPaintEventArgs pe = new DoubleBufferedPaintEventArgs(CreateGraphics(), e.ClipRectangle);
            OnPaint(pe);
            pe.Graphics.Dispose();
            e.Graphics.DrawImage(backBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
            base.OnPaint(e);
        }
        else
        {
            DoubleBufferedPaintEventArgs pe = new DoubleBufferedPaintEventArgs(e.Graphics, e.ClipRectangle);
            OnPaint(pe);
            base.OnPaint(e);
        }
    }

    /// <summary>
    /// Raises the Paint event for child classes that are to be double buffered
    /// </summary>
    /// <param name="e"></param>
    protected virtual void OnPaint(DoubleBufferedPaintEventArgs e)
    {
        if (BufferedPaint != null)
            BufferedPaint(this, e);
    }

    /// <summary>
    /// Paints the background of the control
    /// </summary>
    /// <param name="e">A PaintEventArgs object that contains event data</param>
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        // do not use arg, because can't control back/screen
        Graphics gfx = CreateGraphics();
        gfx.Clear(BackColor);
        gfx.Dispose();
    }

    /// <summary>
    /// Raises the Resize event
    /// </summary>
    /// <param name="e">An EventArgs that represents event data</param>
    protected override void OnResize(System.EventArgs e)
    {
        if (Size != oldSize) // Stupid control gets resized when like anything happens to the parent form
        {
            if (doubleBuffered)
            {
                if (backBuffer != null)
                    backBuffer.Dispose();

                backBuffer = new Bitmap(Width != 0 ? Width : 1, Height != 0 ? Height : 1);
            }
        }
        oldSize = Size;

        base.OnResize(e);
    }

    /// <summary>
    /// Creates the Graphics for the control
    /// </summary>
    /// <param name="backBuffer">True to bypass the buffer and get the control graphics</param>
    /// <returns></returns>
    public virtual Graphics CreateGraphics(bool bypass)
    {
        if(bypass || !doubleBuffered)
            return base.CreateGraphics();
        else
            return Graphics.FromImage(backBuffer);
    }
    public virtual new Graphics CreateGraphics()
    {
        return CreateGraphics(false);
    }
}
  

и вам понадобятся эти:

 /// <summary>
/// Provides data for the DoubleBufferedControl.Paint event
/// </summary>
public class DoubleBufferedPaintEventArgs : PaintEventArgs
{
    /// <summary>
    /// Initializes a DoubleBufferedPaintEventArgs
    /// </summary>
    /// <param name="g">The Graphics object to paint to;  If the control is double buffered, the graphics object is for the buffer otherwise the screens graphics is used</param>
    /// <param name="clip">The region in which to paint</param>
    public DoubleBufferedPaintEventArgs(Graphics g, Rectangle clip) : base(g, clip) { }
}
public delegate void BufferedPaintEventHandler(object sender, DoubleBufferedPaintEventArgs args);
  

Обычно я наследую от этого класса, переопределяю OnPaintBackground метод и оставляю его реализацию пустой. Затем я реализую весь пользовательский чертеж в методе OnPaint.