Для того чтобы включить автоматическую двойную буферизацию, нужно всего лишь для контрола установить свойство DoubleBuffered = true или вызвать SetStyle(ControlStyles.OptimizedDoubleBuffer, true).
Для ручного же управления двойной буферизацией Framework .NET включает 3 класса:
BufferedGraphicsManager содержит одно статическое свойство Current, которое возвращает объект BufferedGraphicsContext для текущего домена приложения.* Для приложений активно использующих анимацию может быть эффективнее создать новый экземпляр BufferedGraphicsContext вместо того чтобы использовать BufferedGraphicsManager.Current. В этом случае по завершению работы с объектом, его необходимо уничтожить явным образом:BufferedGraphicsContext myContext = new BufferedGraphicsContext(); // использование myContext.Dispose();или
using(BufferedGraphicsContext myContext = new BufferedGraphicsContext()) { // использование }BufferedGraphicsContext имеет один метод Allocate и одно свойство MaximumBuffer.
Allocate(Graphics targetGraphics, Rectangle targetRectangle) -- создает новый BufferedGraphics на основе переданного через параметр targetGraphics размером targetRectangle.
Как работает метод Allocate
Исходный код метода:public BufferedGraphics Allocate(Graphics targetGraphics, Rectangle targetRectangle) { if (this.ShouldUseTempManager(targetRectangle)) return this.AllocBufferInTempManager(targetGraphics, IntPtr.Zero, targetRectangle); else return this.AllocBuffer(targetGraphics, IntPtr.Zero, targetRectangle); }Внутри метода происходит проверка MaximumBuffer и targetRectangle (методом ShouldUseTempManager**). Если требуемый размер полотна превышает заданный полем MaximumBuffer , то вызывается метод AllocBufferInTempManager. Этот метод внутри себя создает новый экземпляр класса BufferedGraphicsContext, вызывает у него метод AllocBuffer и возвращает полученный от него объект класса BufferedGraphics.***
Если же targetRectangle не превышает MaximumBuffer, то тогда временный объект не создаётся, а метод AllocBuffer вызывается непосредственно у текущего объекта (т.е. у самого себя).
Метод AllocBuffer внутри себя вызывает метод CreateBuffer, для создания нового экземпляра Graphics, оборачивает его в BufferedGraphics и сохраняет в переменную объекта buffer. Эта переменная используется для того, чтобы в дальнейшем при уничтожении экземпляра BufferedGraphicsContext (методом Dispose), уничтожить связанный с ним экземпляр BufferedGraphics.
Стоит заметить что объект BufferedGraphics также хранит в себе ссылку на создавший его BufferedGraphicsContext в закрытой переменной.
---------------------------------------------------------------
* Код класса BufferedGraphicsManager выглядит следующим образом:
public sealed class BufferedGraphicsManager { private static BufferedGraphicsContext bufferedGraphicsContext; public static BufferedGraphicsContext Current { get { return BufferedGraphicsManager.bufferedGraphicsContext; } } static BufferedGraphicsManager() { AppDomain.CurrentDomain.ProcessExit += new EventHandler(BufferedGraphicsManager.OnShutdown); AppDomain.CurrentDomain.DomainUnload += new EventHandler(BufferedGraphicsManager.OnShutdown); // В СТАТИЧЕСКОМ КОНСТРУКТОРЕ ПРОСТО СОЗДАЕТСЯ НОВЫЙ // НОВЫЙ ОБЪЕКТ BufferedGraphicsContext BufferedGraphicsManager.bufferedGraphicsContext = new BufferedGraphicsContext(); } private BufferedGraphicsManager() { } [PrePrepareMethod] private static void OnShutdown(object sender, EventArgs e) { BufferedGraphicsManager.Current.Invalidate(); } }
** Исходный код метода ShouldUseTempManager():
private bool ShouldUseTempManager(Rectangle targetBounds) { return targetBounds.Width * targetBounds.Height > this.MaximumBuffer.Width * this.MaximumBuffer.Height; }*** При этом созданный внутри метода AllocBufferInTempManager экземпляр BufferedGraphicsContext не уничтожается, ответственность за его уничтожение ложится на пользователя получившего объект BufferedGraphics, который хранит обратную ссылку, при уничтожении которого и уничтожается породиший его объект BufferedGraphicsContext. Как это работает? Исходный код метода AllocBufferInTempManager:
private BufferedGraphics AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) { BufferedGraphicsContext bufferedGraphicsContext = (BufferedGraphicsContext) null; BufferedGraphics bufferedGraphics = (BufferedGraphics) null; try { // Создаем новый "временный" контент bufferedGraphicsContext = new BufferedGraphicsContext(); if (bufferedGraphicsContext != null) // Всегда ДА { // Создаем в нем буферизированное полотно, которое внутри себя (переменная context) хранит // ссылку на него же bufferedGraphics = bufferedGraphicsContext.AllocBuffer(targetGraphics, targetDC, targetRectangle); // ВОТ, этот флаг указывает, что объект bufferedGraphics // при своем уничтожении должен уничтожить породившего его // bufferedGraphicsContext: bufferedGraphics.DisposeContext = true; } } finally { // В нормальной ситуации это условие не выполняется if (bufferedGraphicsContext != null && (bufferedGraphics == null || bufferedGraphics != null && !bufferedGraphics.DisposeContext)) bufferedGraphicsContext.Dispose(); } return bufferedGraphics; }
Комментариев нет:
Отправить комментарий