I'm building custom user control that is based on ScrollableControl.
Right now I'm trying to add border around my control (similar to border that DataGridView has)
I'm able to draw border using:
e.Graphics.TranslateTransform(AutoScrollPosition.X*-1, AutoScrollPosition.Y*-1);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Dashed);
but this draws border around ClientRectangle, not around whole control:

As you can see in the above picture, border isn't surrounding scrollbars as it does in DataGridView.
Can I draw border around entire control so that scrollbars get included in area surrounded by border?
EDIT:
Based on Textbox custom onPaint I am able to draw custom border, by overriding WndProc but I get this weird looking border flickering:
Here is full code I have so far:
internal class TestControl : ScrollableControl
{
private int _tileWidth = 100;
private int _tileHeight = 100;
private int _tilesX = 20;
private int _tilesY = 20;
public TestControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
ResizeRedraw = true;
AutoScrollMinSize = new Size(_tilesX*_tileWidth, _tilesY*_tileHeight);
}
private bool _test = true;
[DefaultValue(true)]
public bool Test
{
get { return _test; }
set
{
if(_test==value) return;
_test = value;
Update();
}
}
[DllImport("user32")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
struct RECT
{
public int left, top, right, bottom;
}
struct NCCALSIZE_PARAMS
{
public RECT newWindow;
public RECT oldWindow;
public RECT clientWindow;
IntPtr windowPos;
}
int clientPadding = 1;
int actualBorderWidth = 1;
Color borderColor = Color.Black;
protected override void WndProc(ref Message m)
{
//We have to change the clientsize to make room for borders
//if not, the border is limited in how thick it is.
if (m.Msg == 0x83 && _test) //WM_NCCALCSIZE
{
if (m.WParam == IntPtr.Zero)
{
RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
rect.left += clientPadding;
rect.right -= clientPadding;
rect.top += clientPadding;
rect.bottom -= clientPadding;
Marshal.StructureToPtr(rect, m.LParam, false);
}
else
{
NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS));
rects.newWindow.left += clientPadding;
rects.newWindow.right -= clientPadding;
rects.newWindow.top += clientPadding;
rects.newWindow.bottom -= clientPadding;
Marshal.StructureToPtr(rects, m.LParam, false);
}
}
if (m.Msg == 0x85 && _test) //WM_NCPAINT
{
base.WndProc(ref m);
IntPtr wDC = GetWindowDC(Handle);
using (Graphics g = Graphics.FromHdc(wDC))
{
ControlPaint.DrawBorder(g, new Rectangle(0, 0, Size.Width, Size.Height), borderColor, actualBorderWidth, ButtonBorderStyle.Solid,
borderColor, actualBorderWidth, ButtonBorderStyle.Solid, borderColor, actualBorderWidth, ButtonBorderStyle.Solid,
borderColor, actualBorderWidth, ButtonBorderStyle.Solid);
}
return;
}
base.WndProc(ref m);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
e.Graphics.TranslateTransform(AutoScrollPosition.X, AutoScrollPosition.Y);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
var offsetX = (AutoScrollPosition.X*-1)/_tileWidth;
var offsetY = (AutoScrollPosition.Y*-1)/_tileHeight;
var visibleX = Width/_tileWidth + 2;
var visibleY = Height/_tileHeight + 2;
var x = Math.Min(visibleX + offsetX, _tilesX);
var y = Math.Min(visibleY + offsetY, _tilesY);
for (var i = offsetX; i < x; i++)
{
for (var j = offsetY; j < y; j++)
{
e.Graphics.FillRectangle(Brushes.Beige, new Rectangle(i*_tileWidth, j*_tileHeight, _tileWidth, _tileHeight));
e.Graphics.DrawString(string.Format("{0}:{1}", i, j), Font, Brushes.Black, new Rectangle(i*_tileWidth, j*_tileHeight, _tileWidth, _tileHeight));
}
}
using (var p = new Pen(Color.Black))
{
for (var i = offsetX + 1; i < x; i++)
{
e.Graphics.DrawLine(p, i*_tileWidth, 0, i*_tileWidth, y*_tileHeight);
}
for (var i = offsetY + 1; i < y; i++)
{
e.Graphics.DrawLine(p, 0, i*_tileHeight, x*_tileWidth, i*_tileHeight);
}
}
e.Graphics.FillRectangle(Brushes.White, AutoScrollPosition.X*-1 + 10, AutoScrollPosition.Y*-1 + 10, 35, 14);
e.Graphics.DrawString("TEST", DefaultFont, new SolidBrush(Color.Red), AutoScrollPosition.X*-1 + 10, AutoScrollPosition.Y*-1 + 10);
e.Graphics.TranslateTransform(AutoScrollPosition.X*-1, AutoScrollPosition.Y*-1);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Red, actualBorderWidth, ButtonBorderStyle.None,
Color.Red, actualBorderWidth, ButtonBorderStyle.None, Color.Red, actualBorderWidth, ButtonBorderStyle.Solid,
Color.Red, actualBorderWidth, ButtonBorderStyle.Solid);
}
protected override void OnScroll(ScrollEventArgs e)
{
if (DesignMode)
{
base.OnScroll(e);
return;
}
if (e.Type == ScrollEventType.First)
{
LockWindowUpdate(Handle);
}
else
{
LockWindowUpdate(IntPtr.Zero);
Update();
if (e.Type != ScrollEventType.Last) LockWindowUpdate(Handle);
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift)
{
VScroll = false;
LockWindowUpdate(Handle);
base.OnMouseWheel(e);
LockWindowUpdate(IntPtr.Zero);
Update();
VScroll = true;
}
else
{
LockWindowUpdate(Handle);
base.OnMouseWheel(e);
LockWindowUpdate(IntPtr.Zero);
Update();
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool LockWindowUpdate(IntPtr hWnd);
}
Can this flickering be fixed?



