i have a Windows Forms application which should be borderless (even without the titlebar) and be resizeable and moveable.
so far, i've set the BorderStyle to 'none' which removes all the borders and let my program look pretty.
Now i've added invisble borders with the following:
private const int cGrip = 16; // Grip size
private const int cCaption = 50; // Caption bar height;
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
//e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x84)
{ // Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32());
pos = this.PointToClient(pos);
if (pos.Y < cCaption)
{
m.Result = (IntPtr)2; // HTCAPTION
return;
}
if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
}
base.WndProc(ref m);
}
Program Layout
The blue rectangle is rendered via the OnPaint() method and shows the field where the user is able to move the window while holding the left mouse button.
My problem is, that this rectangle is below my label.
Does anyone know how to get the rectangle in front of the label?
Another way would be disabling the label which than turns dark grey.
You would solve my problem if i could change the color of my disabled label.
Leave the Label enabled and make it so that dragging the label causes the form to be dragged as well:
public const int HT_CAPTION = 0x2;
public const int WM_NCLBUTTONDOWN = 0xA1;
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
private void label1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(this.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
Related
I've made a custom TextBox class to have a text box with custom border in my application, based on this other SO post. If I set any of the new custom properties in the form designer, they appear momentarily, until I change the control focus, and when I run the application, the new border settings are not displayed. I did update my form's InitializeComponent method, so that the text box initializes a new BorderedTextBox instead of TextBox. Does anyone know what's wrong here?
public class BorderedTextBox : TextBox
{
private Color _borderColor = Color.Black;
private int _borderWidth = 2;
private int _borderRadius = 5;
public BorderedTextBox() : base()
{
InitializeComponent();
this.Paint += this.BorderedTextBox_Paint;
}
public BorderedTextBox(int width, int radius, Color color) : base()
{
this._borderWidth = Math.Max(1, width);
this._borderColor = color;
this._borderRadius = Math.Max(0, radius);
InitializeComponent();
this.Paint += this.BorderedTextBox_Paint;
}
public Color BorderColor
{
get => this._borderColor;
set
{
this._borderColor = value;
DrawTextBox();
}
}
public int BorderWidth
{
get => this._borderWidth;
set
{
if (value > 0)
{
this._borderWidth = Math.Min(value, 10);
DrawTextBox();
}
}
}
public int BorderRadius
{
get => this._borderRadius;
set
{ // Setting a radius of 0 produces square corners...
if (value >= 0)
{
this._borderRadius = value;
this.DrawTextBox();
}
}
}
private void BorderedTextBox_Paint(object sender, PaintEventArgs e) => DrawTextBox(e.Graphics);
private void DrawTextBox() => this.DrawTextBox(this.CreateGraphics());
private void DrawTextBox(Graphics g)
{
Brush borderBrush = new SolidBrush(this.BorderColor);
Pen borderPen = new Pen(borderBrush, (float)this._borderWidth);
Rectangle rect = new Rectangle(
this.ClientRectangle.X,
this.ClientRectangle.Y,
this.ClientRectangle.Width - 1,
this.ClientRectangle.Height - 1);
// Clear text and border
g.Clear(this.BackColor);
// Drawing Border
g.DrawRoundedRectangle(
borderPen,
(0 == this._borderWidth % 2) ? rect.X + this._borderWidth / 2 : rect.X + 1 + this._borderWidth / 2,
rect.Y,
rect.Width - this._borderWidth,
(0 == this._borderWidth % 2) ? rect.Height - this._borderWidth / 2 : rect.Height - 1 - this._borderWidth / 2,
(float)this._borderRadius);
}
#region Component Designer generated code
/// <summary>Required designer variable.</summary>
private System.ComponentModel.IContainer components = null;
/// <summary>Clean up any resources being used.</summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
/// <summary>Required method for Designer support - Don't modify!</summary>
private void InitializeComponent() => components = new System.ComponentModel.Container();
#endregion
}
You need to override WndProc:
private const int WM_PAINT = 0x000F;
protected override void WndProc( ref Message m ) {
if(m.Msg == WM_PAINT ) {
base.WndProc( ref m );
Graphics gr = this.CreateGraphics();
//draw what you want
gr.Dispose();
return;
}
base.WndProc( ref m );
}
Works fine without any issues. It draws in client area though. A complete version drawing a custom border, textbox need to have border:
[DllImport( "user32.dll" )]
static extern IntPtr GetWindowDC( IntPtr hWnd );
[DllImport( "user32.dll" )]
static extern bool ReleaseDC( IntPtr hWnd, IntPtr hDC );
[DllImport( "gdi32.dll" )]
static extern bool FillRgn( IntPtr hdc, IntPtr hrgn, IntPtr hbr );
[DllImport( "gdi32.dll" )]
static extern IntPtr CreateRectRgn( int nLeftRect, int nTopRect, int nRightRect,
int nBottomRect );
[DllImport( "gdi32.dll" )]
static extern IntPtr CreateSolidBrush( uint crColor );
[DllImport( "gdi32.dll" )]
static extern bool DeleteObject( IntPtr hObject );
private const int WM_NCPAINT = 0x0085;
private const int WM_PAINT = 0x000F;
private const int RGN_DIFF = 0x4;
private int p_border = 2;
protected override void WndProc( ref Message m ) {
if(m.Msg == WM_PAINT ) {
base.WndProc( ref m );
IntPtr hdc = GetWindowDC( this.Handle ); //gr.GetHdc();
IntPtr rgn = CreateRectRgn( 0, 0, this.Width, this.Height );
IntPtr brush = CreateSolidBrush( 0xFF0000 ); //Blue : B G R
CombineRgn( rgn, rgn, CreateRectRgn( p_border, p_border, this.Width - p_border,
this.Height - p_border ), RGN_DIFF );
FillRgn( hdc, rgn, brush );
ReleaseDC( this.Handle, hdc );
DeleteObject( rgn );
DeleteObject( brush );
m.Result = IntPtr.Zero;
return;
}
if( m.Msg == WM_NCPAINT ) {
return;
}
base.WndProc( ref m );
}
Winforms TextBox is a legacy control I think even from way back before the .Net framework.
It doesn't support owner-drawing and as one can see on MSDN neither Paint not OnPaint are documented to work.
Yes, you can code them, and yes, they will have some effect. But TextBox doesn't play by the normal rules and will mess up your drawing without triggering a paint event.
Possibly you can hook yourself into the windows message queue (WndProc) but it is generally not recommended, especially for something like adorning it with a border.
Usually nesting a TextBox in a Panel and letting the Panel draw a nice Border is the simplest solution..
I am currently busy developing a borderless WinForms form, and I have just gotten some code from here. I modified it to my needs, but I am now stuck. How would I put a limit as to how much it can resize?
Currently, I can resize my window so that it is a mere dot on the screen. How can I put a "cap" on the minimum size?
Here is a snippet of the code used for the resizer(should work as is):
//Initializes the form
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
private const int cGrip = 16; // Grip size
private const int cCaption = 32; // Caption bar height;
//Overides what happens everytime the form is drawn
protected override void OnPaint(PaintEventArgs e)
{
//Draws a border with defined width
int width = 1;
Pen drawPen = new Pen(titleBar.BackColor, width);
e.Graphics.DrawRectangle(drawPen, new Rectangle(width / 2, width / 2, this.Width - width, this.Height - width));
drawPen.Dispose();
//Draws the resizer grip
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
e.Graphics.FillRectangle(Brushes.Coral, rc);
}
//Handles windows messages
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x84)
{ // Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32());
pos = this.PointToClient(pos);
//if (pos.Y < cCaption)
//{
// m.Result = (IntPtr)2; // HTCAPTION
// return;
//}
if (
pos.X >= this.ClientSize.Width - cGrip &&
pos.Y >= this.ClientSize.Height - cGrip)
{
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
}
base.WndProc(ref m);
}
Just as a note, I'm not a very seasoned C# programmer. My only previous experience in C# was programming in Unity, so I would appreciate if you could give me a detailed explanation of what solution you might have.
Regardless of the Form being borderless or not, you can still use the MinimumSize and MaximumSize properties.
Try this:
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.MinimumSize = new Size(200, 200);
this.MaximumSize = new Size(800, 600);
}
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?
I was able to solve my problem by overriding CreateParams:
protected override CreateParams CreateParams
{
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= NativeMethods.WS_EX_CONTROLPARENT;
cp.ExStyle &= (~NativeMethods.WS_EX_CLIENTEDGE);
cp.Style &= (~NativeMethods.WS_BORDER);
cp.Style |= NativeMethods.WS_BORDER;
return cp;
}
}
and here is required NativeMethods class:
internal static class NativeMethods
{
public const int WS_EX_CONTROLPARENT = 0x00010000;
public const int WS_EX_CLIENTEDGE = 0x00000200;
public const int WS_BORDER = 0x00800000;
}
below is the result:
You can simply derive from UserControl. It has built-in support for showing scrollbars and also has built-in support for showing borders.
All of built-in features of UserControl can be added to your control which is derived from ScrollableControl but with some additional try and error effort or taking look at source code of UserControl. But using UserControl class you can simply have those features.
Show Border
To show border, it's enough to set its BorderStyle to FixedSingle to get desired feature:
Show Scrollbars
To gain scroll feature, it's enough to set its AutoScroll to true and also set a suitable AutoScrollMinSize for control. Then when the width or height of the control is less than width or height of given size, the suitable scrollbar will be shown.
Custom Border Color
I also suppose you want to have different border color for the control, then it's enough to override WndProc and handle WM_NCPAINT and draw custom border for the control like this:
In above example, I've used the same technique which I used for Changing BorderColor of TextBox with a small change, here I checked if the BorderStyle equals to FixedSingle the I drew the border with desired color.
Enable the designer to act like a Parent Control at design time
If you want to enable it's designer to be able to drop some controls onto your UserControl, it's enough to decorate it with [Designer(typeof(ParentControlDesigner))]. This way, when you drop your UserControl on form, it can host other controls like a panel control. If you don't like this feature, just don't decorate it with that attribute and it will use Control designer by default which doesn't act like a parent control.
I have WPF borderless Transparent window.
By using this.DragMove(); I can successfully move the window.
I wanted to restrict window within screen area.
It's also working using below snippet.
private void Window_LocationChanged(object sender, EventArgs e)
{
CheckBounds();
}
private void CheckBounds()
{
var height = System.Windows.SystemParameters.PrimaryScreenHeight;
var width = System.Windows.SystemParameters.PrimaryScreenWidth;
if (this.Left < 0)
this.Left = 0;
if (this.Top < 0)
this.Top = 0;
if (this.Top + this.Height > height)
this.Top = height - this.Height;
if (this.Left + this.Width > width)
this.Left = width - this.Width;
}
But using above code, whenever window reach its max bounds using mouse drag, It starts flickering.
Could anybody suggest how to avoid this flickering?
The best way I know to deal with this issue is to handle the WM_MOVING windows message in your window and adjust the position there. Since the WM_MOVING message is received before the window actually moves and allows the position to be modified, you never see any jitter. Here is an example code-behind for a Window.
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
public partial class MainWindow : Window
{
private HwndSource mSource;
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
mSource = (HwndSource)PresentationSource.FromVisual(this);
mSource.AddHook(WndProc);
}
protected override void OnClosed(EventArgs e)
{
mSource.RemoveHook(WndProc);
mSource.Dispose();
mSource = null;
base.OnClosed(e);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == (int)WindowsMessage.WM_MOVING)
{
// TODO: Substitute realistic bounds
RECT bounds = new RECT() { Left = 0, Top = 0, Right = 1000, Bottom = 800 };
RECT window = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
if (window.Left < bounds.Left)
{
window.Right = window.Right + bounds.Left - window.Left;
window.Left = bounds.Left;
}
if (window.Top < bounds.Top)
{
window.Bottom = window.Bottom + bounds.Top - window.Top;
window.Top = bounds.Top;
}
if (window.Right >= bounds.Right)
{
window.Left = bounds.Right - window.Right + window.Left - 1;
window.Right = bounds.Right - 1;
}
if (window.Bottom >= bounds.Bottom)
{
window.Top = bounds.Bottom - window.Bottom + window.Top - 1;
window.Bottom = bounds.Bottom - 1;
}
Marshal.StructureToPtr(window, lParam, true);
handled = true;
return new IntPtr(1);
}
handled = false;
return IntPtr.Zero;
}
}
Here are the helper objects that are used in the code:
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left, Top, Right, Bottom;
}
enum WindowsMessage
{
WM_MOVING = 0x0216
}
P.S. The LocationChanged event (and associated OnLocationChanged override) is called in response to WM_MOVE, which is not called until the window has already moved. There does not seem to be a corresponding OnLocationChanging event.
I guess this is generic issue and not limited to ComboBox, however I have specifically problem with ComboBox. I extended ComboBox object with MyCB MyCB : ComboBox)
What happens is every time I hover over the control, leave the control, expand selection box or select a value, the control flickers. For a short while I can see default (non-replaced) control which is being instantly replaced with mine.
I believe what's happening is that Windows first draws the "original" control (by calling base.WndProc()) and then repaints it with mine.
The question is, can I somehow stop windows from painting it's own control and instantly paint mine?
Below is code overriding WndProc
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT)
{
Graphics gg = this.CreateGraphics();
gg.FillRectangle(BorderBrush, this.ClientRectangle);
// ... //
//Draw the arrow
gg.FillPath(ArrowBrush, pth);
// ... //
if(this.Text == "")
gg.DrawString("-- SELECT --", this.Font, new SolidBrush(Color.Black), rf, sf);
else
gg.DrawString(this.Text, this.Font, new SolidBrush(Color.Black), rf, sf);
gg.Dispose();
}
}
What have I tried so far:
I know that I can't do this:
if (m.Msg == WM_PAINT)
{
...
}
else
{
base.WndProc(ref m);
}
as that will cause control to repaint itself infinitely (not sure why)
I was able to remove flickering which happened when mouse leaves/enters the control by adding this code
if (m.Msg == WM_MOUSEFIRST || m.Msg == WM_MOUSELEAVE) // 0x0200 0x02A3
{
m.Result = (IntPtr)1;
}
else
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT)
{
...
}
}
however this doesn't solve the problem completely
I looked into ILSpy to check on ComboBox's WndProc but there were so many windows messages that I didn't know which of those I could possibly immitate to achive my goal
public CustomComboBox()
{
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == Win32.WM_MOUSEFIRST || m.Msg == Win32.WM_MOUSELEAVE || m.Msg == Win32.WM_MOUSEHOVER) //0x0200, 0x02A3, 0x02A1
{
m.Result = (IntPtr)1;
return;
}
base.WndProc(ref m);
if (m.Msg == Win32.WM_PAINT)
{
IntPtr hDC = Win32.GetWindowDC(m.HWnd);
Graphics g = Graphics.FromHdc(hDC);
g.SmoothingMode = SmoothingMode.HighSpeed;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
if (Text.Length == 0)
{
StringFormat stringFormat = new StringFormat
{
Alignment = StringAlignment.Near,
LineAlignment = StringAlignment.Near
};
g.DrawString("Water Marks", Font, new SolidBrush(Color.FromArgb(51, 51, 51)), (Bounds.Width - 2), FontHeight + 2, stringFormat);
}
Pen border = new Pen(ui_BorderLineColor, 1);
g.DrawRectangle(border, 0, 0, this.Width - 1, this.Height - 1);
g.Dispose();
Win32.ReleaseDC(m.HWnd, hDC);
}
}
protected override void InitLayout()
{
base.InitLayout();
DropDownStyle = ComboBoxStyle.DropDownList; //Works only in DropDownList
}
// Edit completing Moses comment
public class Win32
{
public const int WM_MOUSEFIRST = 0x0200;
public const int WM_MOUSELEAVE = 0x02A3;
public const int WM_MOUSEHOVER = 0x02A1;
public const int WM_PAINT = 0x000F;
[DllImport("user32")]
public static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("user32.dll")]
public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprc, IntPtr hrgn, uint flags);
}