WPF, WinForms: 15000 FPS. Hardcore tricks h.1.5
So, in a nutshell, what has changed: the control and test application for WindowsForms has been added, the WPF option has changed a bit, refactoring has been added, threadsafe has been added and the control can now normally resize in runtime (included in the samples, but I don’t recommend deploying it to full screen - this really scary). Thanks to comrades who pointed out errors and shortcomings, and now the project is proudly 0.5 beta. You can immediately go for an update at razorgdipainter.codeplex.com/ , who are interested in details, I ask for a cat.
We will talk about the WinForms-use case. Almost all control:
private readonly HandleRef hDCRef;
private readonly Graphics hDCGraphics;
private readonly RazorPainter RP;
public Bitmap RazorBMP { get; private set; }
public Graphics RazorGFX { get; private set; }
public RazorPainterWFCtl()
{
InitializeComponent();
this.MinimumSize = new Size(1, 1);
SetStyle(ControlStyles.DoubleBuffer, false);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
hDCGraphics = CreateGraphics();
hDCRef = new HandleRef(hDCGraphics, hDCGraphics.GetHdc());
RP = new RazorPainter();
RazorBMP = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
RazorGFX = Graphics.FromImage(RazorBMP);
this.Resize += (sender, args) =>
{
lock (this)
{
if (RazorGFX != null) RazorGFX.Dispose();
if (RazorBMP != null) RazorBMP.Dispose();
RazorBMP = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
RazorGFX = Graphics.FromImage(RazorBMP);
}
};
}
public void RazorPaint()
{
RP.Paint(hDCRef, RazorBMP);
}
As promised, the code is as simple as a boot. The transfer of GFX and BMP from the test application code to the control code is immediately noteworthy. Thanks to alexanderzaytsev , it’s calmer at heart - it will be more difficult for the front-end programmer to create something indecent with them, and it is easier to work with the resize control.
Lock () in the resize code is also noteworthy. As I mentioned, one of the main advantages of the library is stream independence. We can ignore the UI Thread, and draw on the control from any thread, even from three different ones at the same time. We don’t want anyone to try to draw on the bitmap, which is currently being recreated due to resize?
Respectively, the frontend code of the window application has also changed a bit:
private void Render()
{
lock(razorPainterWFCtl1)
{
razorPainterWFCtl1.RazorGFX.Clear((drawred = !drawred) ? Color.Red : Color.Blue);
razorPainterWFCtl1.RazorGFX.DrawString("habr.ru", this.Font, Brushes.Azure,10,10);
razorPainterWFCtl1.RazorPaint();
}
}
Another lock (), but we can be sure that no one can draw and resize at the same time.
In the WPF-version, almost the same changes. This threadafe implementation is certainly clumsy, but it is suitable for demo test applications.
In WF, when closing a window, an Exception manages to slip through - just change the render cycle, because:
renderthread = new Thread(() =>
{
while (true)
Render();
});
this is a really stupid idea for production. It would be possible to use the control from the WF version as a child control in the WPF version, but something tells me that it is better to separate WPF and WF branches, since with further development, usage features unique to each architecture may arise. But maybe I just scare myself, and in the future the branches will merge.
Use your health under the MIT license, i.e. generally whatever for any purpose. Whoever has a desire - connect to the development of the library on CodePlex .
UPD : Habra-comrades sintez and nile1 convinced to do
///
/// Lock it to avoid resize/repaint race
///
readonly object RazorLock = new object();
with a reservation on the test form // better practice is Monitor.TryEnter () pattern, but here we do it simpler Indeed, it has not become much more complicated, and it became more correct. I updated the codecs on the codex, released 0.6 beta, thank you everyone wrote.