redraw the whole client area - c#

Since a little bit i tried to add a grip to a window to resize it. I follow an example and it works fine for resizing. But my window does paint properly, it seems like it does not clear before redrawing or does not redraw the whole client area.
Here is my code:
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case (int)WinApi.Messages.WM_NCHITTEST:
WinApi.HitTest ht = HitTestNCA(m.HWnd, m.WParam, m.LParam);
if (ht != WinApi.HitTest.HTCLIENT)
{
// ht == HTBOTTOMRIGHT
m.Result = (IntPtr)ht;
return;
}
break;
}
base.WndProc(ref m);
}
the result is here: screenshot

Related

WinForms - Borderless DateTimePicker

I have a stock winform datetimepicker that looks something like this...
I would like to make it look something like this...
The WinForm TextBox has a borderless option and I manually created a horizontal rule to give the illusion of a seamless underlined TextBox but the DateTimePicker doesn't seem to have a borderless option.
Is there something I can do to either make the DateTimePicker look like the example above or at least remove the borders so I can manually place the underline?
To achieve the custom look for the control, you have to override the WndProc method, which is the method that processes all the window messages for this control.
protected override void WndProc(ref Message m)
{
IntPtr hDC = GetWindowDC(m.HWnd);
Graphics gdc = Graphics.FromHdc(hDC);
switch (m.Msg)
{
case WM_NC_PAINT:
SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
SendPrintClientMsg();
SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);
OverrideControlBorder(gdc);
m.Result = (IntPtr)1; // indicate msg has been processed
break;
case WM_PAINT: base.WndProc(ref m);
OverrideControlBorder(gdc);
OverrideDropDown(gdc);
break;
case WM_NC_HITTEST:
base.WndProc(ref m);
if (DroppedDown)
this.Invalidate(this.ClientRectangle, false);
break;
default:
base.WndProc(ref m);
break;
}
ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
}
This is as close as I can get it:
You will have to make an image for the drop down button.
public class SexyDateTimePicker : DateTimePicker
{
public SexyDateTimePicker() : base()
{
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Black, 0, this.ClientSize.Height -1, this.ClientSize.Width, this.ClientSize.Height -1);
e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(Color.Black), 0, 0);
e.Graphics.DrawImage(Properties.Resources.DateOrTimePicker_675, new Point(this.ClientRectangle.X + this.ClientRectangle.Width - 16, this.ClientRectangle.Y));
}
}
The answer with the least amount of code would be to place a panel, place the control in the panel and then "clip" the border of the dateTimePicker (DTP) by reducing the size of the panel.

C# How to drag Form from picturebox or panel?

My problem is simple, I can't drag a window/form from picturebox or panel that is similar to custom toolbar/border.
Basicly you can drag only from background of the form, but not from any control.
Hope you understand my problem. If needed I can make video or pictures.
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x84://Can move window if borders are off.
base.WndProc(ref m);
if ((int)m.Result == 0x1)
m.Result = (IntPtr)0x2;
return;
case 0x00A3: m.Result = IntPtr.Zero; return; //Double click won't zoom in.
}
base.WndProc(ref m);
}

C# Detecting a Click in WndProc and calling a function after click happened

I am trying to detect a click and preform calling a function only after the click actually happened.
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m) {
//Detect a Click
if (m.Msg == 0x210 && m.WParam.ToInt32() == 513){
lastClick = DateTime.Now;
clickedHappened();
Debug.Print("Click Detected!");
}
base.WndProc(ref m);
}
private void clickedHappened(){
MessageBox.Show("Click Already Happened");
}
I think that WndProc happens way before the actual click takes place.
I was wondering if there was a way to solve this with out using a timer? or sleep(400);
The only solution I can come up with is using a timer, but I want to get rid of some of my existing timers. It seems that the click actually happens 200 - 350 ms after it was detected in WndProc.
WndProc is short for Window Procedure, its the procedure that handles everything for the window, drawing, mouse capture, keyboard capture, resizing...
There are also several ways you can capture the mouse for varying results
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case 0x201:
//left button down
break;
case 0x202:
clickedHappened(); //left button up, ie. a click
break;
case 0x203:
//left button double click
break;
}
base.WndProc(ref m);
}
The thing is, windows forms in C# already handles all of these for you and from the WndProc, fires events there is no real need to handle WndProc yourself for this type of thing.
For a full list of mouse notification messages, see MSDN: Mouse Input Notifications and for a list of all wndproc messages, see MSDN System Defined Messages
Probably, you can handle WM_LBUTTONUP message that occured after click.
You can do it like this:
const int WM_LBUTTONUP = 0x202;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONUP)
{
clickedHappened();
}
base.WndProc(ref m);
}

Winforms - WM_NCHITEST message for click on control

I have a simple windows form with no border and several label controls (nothing that needs to be clicked). I needed to be able to allow the user to move the form by clicking anywhere on it, so I found this question, and used the following code found there.
private const int WM_NCHITTEST = 0x84;
private const int HTCLIENT = 0x1;
private const int HTCAPTION = 0x2;
protected override void WndProc(ref Message m)
{
switch (m.Msg) {
case WM_NCHITTEST:
base.WndProc(ref m);
if ((int)m.Result == HTCLIENT) {
m.Result = (IntPtr)HTCAPTION;
return;
} else {
return;
}
break;
}
base.WndProc(ref m);
}
This works well...to a point. If I click anywhere on the form itself (the background), WM_NCHITTEST is HTCLIENT, so I can move my form as expected. However, if I click on a label control itself, the message is something different, and I can't tell what it is.
I found this article about the various possible values for WM_NCHITTEST but none of them seem to be what I need.
I realize I could disable all my label controls and that would allow me to click "on" them as if it was the form itself, but I'm wondering if there's a better/different way to do this.
Thanks for the help!
You are overriding the WndProc for the form, but when the cursor is over a label the WM_NCHITTEST message is sent to the label.
You could create your own label control derived from Label and override its WndProc. This should always return HTTRANSPARENT in response to WM_NCHITTEST. Something like:
private const int HTTRANSPARENT = -1;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCHITTEST:
m.Result = (IntPtr)HTTRANSPARENT;
return;
}
base.WndProc(ref m);
}
Also note that there's a small bug in your WndProc. If the message is WM_NCHITTEST but the region isn't HTCLIENT then you call the base class twice.

C# MouseEnter-Event for the whole window

Is it possible to create a MouseEnter-Event also for the border of the window? I mean also for the minimize and maximize-buttons. Because if I set the Event for my Form1, it works only when i'm inside the Form, but not on the border and the Buttons.
You can override WndProc in you form and you can detect mousemove
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// mouse in window or in Border and max, close & min buttons
if (m.Msg == 0xa0 || m.Msg == 0x200)
{
//Do some thing
}
}

Categories