- PVSM.RU - https://www.pvsm.ru -
Неожиданное продолжение этого поста [1], поэтому часть 2 хардкорных трюков, в которой речь пойдет немного о другом, пока подождет.
Итак, в двух словах, что изменилось: добавлен контрол и тестовое приложение для WindowsForms, вариант WPF немного изменился, рефакторинг-причесалинг, добавился threadsafe и контрол теперь может нормально ресайзиться в рантайме (включено в сэмплы, но не советую разворачивать на полный экран — это реально пугает). Спасибо камрадам, указавшим на ошибки и недостатки и теперь теперь проект гордо 0.5 beta. Можно сразу отправиться за обновлением на razorgdipainter.codeplex.com/ [2], кому интересны подробности прошу под кат.
Речь пойдет о WinForms-варианте использования. Практически весь контрол:
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);
}
Как и обещал, код просто как сапог. Сразу обращает на себя внимание перенос GFX и BMP из кода тестового приложения в код контрола. Спасибо alexanderzaytsev [3], так и на душе спокойнее — фронтэнд-программеру будет сложнее сотворить что-то непотребное с ними, и с ресайзом контрола работать проще.
Еще обращает на себя внимание lock() в коде ресайза. Как я уже упоминал, одно из основных преимуществ библиотеки — потоконезависимость. Мы можем не обращать внимания на UI Thread, и рисовать на контроле из любого потока, хоть из трех разных одновременно. Поэтому lock() -мы ведь не хотим чтобы кто-то пытался рисовать на битмапе, который в данный момент пересоздается?
Соотвественно, фронтэнд-код оконного приложения тоже немного изменился:
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();
}
}
И мы можем быть спокойны, что никто не сможет одновременно и рисовать и ресайзить.
В WPF-варианте практически те-же изменения.
В WF при закрытии окна успевает проскочить Exception, просто измените цикл рендера, потому-что:
renderthread = new Thread(() =>
{
while (true)
Render();
});
это действительно дурацкая идея для продакшна.
Можно было бы в качестве дочернего контрола в WPF-варианте использовать контрол из WF-варианта, но что-то мне подсказывает, что лучше разделить WPF и WF ветки, поскольку при дальнейшем развитии могут возникнуть особенности использования, уникальные для каждой из архитектур. Но, возможно, я просто сам себя пугаю, и в дальнейшем ветки объединятся.
Пользуйтесь на здоровье, у кого есть желание — подключайтесь к развитию библиотеки на CodePlex, предлагайте варианты использования.
Автор: Lincoln6Echo
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/bitmap/24157
Ссылки в тексте:
[1] этого поста: http://habrahabr.ru/post/164705/
[2] razorgdipainter.codeplex.com/: http://razorgdipainter.codeplex.com/
[3] alexanderzaytsev: http://habrahabr.ru/users/alexanderzaytsev/
[4] Источник: http://habrahabr.ru/post/164885/
Нажмите здесь для печати.