Прежде чем я начну, я хотел бы сказать, что я согласен с Xaero по его вопросу. Кажется, что ваша намеченная цель выиграет от класса ErrorProvider.
Тем не менее, вы можете инвертировать содержимое графической области, используя BitBlt через P / Invoke. Вот функция, которая может сделать это для вас, но без оптимизации. Я оставлю эту часть на ваше усмотрение. Эта функция использует растровые операции для инвертирования целевой области. XOR с белым источником на месте назначения приводит к инвертированию цветов в месте назначения (по логическому значению, а не по цветовому пространству).
private void InvertGraphicsArea(Graphics g, Rectangle r)
{
if (r.Height <= 0) { return; }
if (r.Width <= 0) { return; }
using (Bitmap bmpInvert = GetWhiteBitmap(g, r))
{
IntPtr hdcDest = g.GetHdc();
using (Graphics src = Graphics.FromImage(bmpInvert))
{
int xDest = r.Left;
int yDest = r.Top;
int nWidth = r.Width;
int nHeight = r.Height;
IntPtr hdcSrc = src.GetHdc();
BitBlt(hdcDest, xDest, yDest, nWidth, nHeight,
hdcSrc, 0, 0, (uint)CopyPixelOperation.DestinationInvert);
src.ReleaseHdc(hdcSrc);
}
g.ReleaseHdc(hdcDest);
}
}
В классе, который содержит эту служебную функцию, вам необходимо импортировать System.Runtime.InteropServices, а также определение BitBlt (). Кроме того, внутренняя часть этой функции немного более лаконична с помощью вспомогательного метода GetWhiteBitmap ().
using System.Runtime.InteropServices;
// ...
[DllImport("gdi32.dll",
EntryPoint="BitBlt",
CallingConvention=CallingConvention.StdCall)]
extern public static int BitBlt(
IntPtr hdcDesc, int nXDest, int nYDest, int nWidth, int nHeight,
IntPtr hdcSrc, int nXSrc, int nYSrcs, uint dwRop);
private Bitmap GetWhiteBitmap(Graphics g, Rectangle r)
{
int w = r.Width;
int h = r.Height;
Bitmap bmp = new Bitmap(w, h);
using (Graphics gTmp = Graphics.FromImage(bmp))
{
gTmp.Clear(Color.White);
}
return bmp;
}
Это не настоящая инверсия преобразования цветов на графической поверхности, но это в значительной степени аналогично тому, как были сделаны блики в старые времена win32. Чтобы проверить это, я взломал приложение WinForms по умолчанию и добавил следующий код, который обрабатывает двойной щелчок, рисует и имеет переменную-член для альтернативного состояния.
bool m_Highlight = false;
private void Form1_DoubleClick(object sender, EventArgs e)
{
m_Highlight = !m_Highlight;
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Note: sloppy, but just to show that everything is inverted.
using(Font font = new Font(FontFamily.GenericSerif, 20.0f, FontStyle.Bold))
{
e.Graphics.DrawString("Hello World!", font, Brushes.Red, 0.0f, 0.0f);
}
if (m_Highlight)
{
InvertGraphicsArea(e.Graphics, e.ClipRectangle);
}
}