【问题标题】:Double buffering on .NET Compact Framework.NET Compact Framework 上的双缓冲
【发布时间】:2014-08-08 00:56:51
【问题描述】:

我想知道是否有人可以向我解释如何在 .net 紧凑框架中双重缓冲完整的表单。我找到了双缓冲的例子,但我似乎无法让其中任何一个工作。

我们创建了一个包含多个表单的应用程序。其中一些表格确实需要很长时间才能在屏幕上绘制,从而导致闪烁。为了让您深入了解我们的应用程序,我将解释其中一种形式。 此表单包含一个用户控件、一些面板、文本框和按钮。 用户控件的面板具有自定义绘图(在屏幕上绘制文本和图像(具有透明度))。甚至其中一些面板还包含执行相同操作的其他面板。 面板也有自定义绘图,因为我们在屏幕上绘制带有一些效果等的文本。 每个面板都需要时间来绘制,这意味着如果我们在 3x3 网格中有 9 个面板,它们会被绘制并以随机顺序显示,而不是同时显示。文本绘制等也是如此。我们希望表单上的所有内容都同时显示。

所以我的问题是,我可以创建一个执行双缓冲的“超级”类,在内存中绘制完整的表格吗?

我可以从它扩展我的当前表单,而无需对我的控件、面板、图像绘制等进行任何更改吗?

谢谢

【问题讨论】:

  • 我只知道图像的双缓冲,而不是按钮、输入字段等 Windows 元素。您可以在内存中保存一堆表单,然后在它们之间快速切换。 MSDN 上有一个示例。

标签: c# .net windows-mobile compact-framework doublebuffered


【解决方案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 && !doubleBuffered && Width > 0 && Height > 0)
            {
                backBuffer = new Bitmap(Width, Height);
            }
            else if(!value && 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 方法中实现所有自定义绘图。

【讨论】:

    猜你喜欢
    • 2010-11-14
    • 1970-01-01
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 2020-05-14
    • 2012-12-22
    相关资源
    最近更新 更多