Для того чтобы включить автоматическую двойную буферизацию, нужно всего лишь для контрола установить свойство 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;
}
Комментариев нет:
Отправить комментарий