Show a custom calendar dropdown with a derived DateTimePicker class - c#

My goal is to create a custom DateTimePicker class in .NET 2.0, which shows a custom calendar dropdown instead of the Windows default calendar popup.
By observing Windows messages (see attached code), I am able to find and hide/close the calendar window after creation.
However, a problem remains: After the calendar window is closed, something is still blocking the mouse input. For example, if you try to maximise the owner form of the customised DateTimePicker control after the calendar dropdown has been closed programmatically (attached code), the maximise button does not respond. Only the next click works. Interestingly, the "non-functional click" fires the DTN_CLOSEUP notification, so it appears that the WM_CLOSE did not properly close the calendar.
Any hints on how to accomplish my task are highly appreciated :)
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == (int)SYSMSG.WM_REFLECT + (int)SYSMSG.WM_NOTIFY)
{
NMHDR nmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
switch (nmhdr.code)
{
case DTN_DROPDOWN:
// Hide window
IntPtr calHandle = FindWindow("SysMonthCal32", null);
SendMessage(calHandle, (int)SYSMSG.WM_SIZE, 0, SP.Convert.MakeLong(0, 0));
this.BeginInvoke((MethodInvoker)delegate()
{
SendMessage(calHandle, (int)SYSMSG.WM_CLOSE, 0, 0);
});
break;
}
}
base.WndProc(ref m);
}

Instead of sending a WM_CLOSE have you tried sending a DTM_CLOSEMONTHCAL message instead? You would send this to the HWND of the DateTimePicker itself and not the child window. According to the documentation, the DateTime_CloseMonthCal macro sends this message and it seems like what you want to do.
I also don't think you'll need to use BeginInvoke to send it unless there's some problem with closing it in the same dispatch as a drop down notification.
#define DTM_FIRST 0x1000
#define DTM_CLOSEMONTHCAL (DTM_FIRST + 13)
#define DateTime_CloseMonthCal(hdp) SNDMSG(hdp, DTM_CLOSEMONTHCAL, 0, 0)

I finally found this fully customisable datePicker (monthCalendar rendering is override-able) : Culture Aware Month Calendar and Datepicker on CodeProject

Related

How to supress user actions on a ListBox control

Suppose we have a control (e.g. ListBox) and need to lock it from mouse clicks and keyboard actions. Of course, there is a standard property Enabled, but it causes appearance change, undesirable in my case.
I have found a simple solution using Windows API, see below. Suprisingly I haven't found a similar question exactly for my task so let me share this obvious solution with the community.
Any additions and comments are appreciated. In case someone will propose more appropriate/shorter/nicer answer.
We can use Windows API to lock our control from user actions.
First we should find out what standard WinAPI messages will be supressed while posting to the control. In my particular case of ListBox control I have chosen WM_LBUTTONDOWN, WM_KEYDOWN and WM_SETFOCUS messages (see docs), to lock both mouse and keyboard button presses and prevent my control from focusing.
Second we create a derived control class based on the ListBox, in the same namespace for convenience:
public class LockableListbox : ListBox
{
public bool Locked { get; set; }
const int WM_LBUTTONDOWN = 0x0201;
const int WM_SETFOCUS = 0x0007;
const int WM_KEYDOWN = 0x0100;
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
if (Locked)
switch (m.Msg)
{
case WM_LBUTTONDOWN:
case WM_KEYDOWN:
case WM_SETFOCUS:
return;
}
base.WndProc(ref m);
}
}
Here the standard WndProc method of the control is overridden to stop chosen messages from posting depending on Lock flag state.
Third we just change ListBox to LockableListBox in our Form class designer part where it is required.
Now our modified ListBox will be protected from user actions (mouse clicks, keyboard actions and focusing) when the Lock property is set.

Detect when help button is pressed in title bar of Windows Form?

My c# console application displays a Windows Form for user to login, I've added a Help button to the top of the login Form just in case any users have any questions
What I'm trying to accomplish is have a MessageBox() popup when user presses the Help button. I've done some research and still haven't been able to find any working solutions. Any help would greatly be appreciated!Thank you for your time.
According to MSDN the way to handle this is to process the windows WM_HELP message:
DS_CONTEXTHELP
Includes a question mark in the title bar of the dialog box. When the user clicks the question mark, the cursor changes
to a question mark with a pointer. If the user then clicks a control
in the dialog box, the control receives a WM_HELP message. The control
should pass the message to the dialog box procedure, which should call
the function using the HELP_WM_HELP command. The help application
displays a pop-up window that typically contains help for the control.
Note that DS_CONTEXTHELP is only a placeholder. When the dialog box is
created, the system checks for DS_CONTEXTHELP and, if it is there,
adds WS_EX_CONTEXTHELP to the extended style of the dialog box.
WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or
WS_MINIMIZEBOX styles.
In brief, you need to implement a WndProc method for the controls in your form (which unfortunately will need to be individually derived from their base classes):
const int WM_HELP = 0x53;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_HELP:
// Your handler here
break;
default:
base.WndProc(ref m);
break;
}
}

How to dismiss all WPF menus, popups, etc. by DevExpress programmatically to get around WindowsFormsHost related issue?

I want it to behave such as you clicked somewhere on application. (which collapses all menus, drop downs, etc)
Actually, I'm trying to get around the interoperability related focus issue you get when you are hosting Windows Forms controls in a WPF application using WindowsFormsHost: If a WPF menu/popup by DevExpress is open and you click on a Windows Forms control, the menu/popup doesn't get dismissed automatically.
Now I have a lot of Windows Forms controls in the WindowsFormsHost and also a lot of DevExpress controls in the WPF area. To get around this easily, I have added a message filter to hook all clicks in application and then I see if the clicked control was a Windows Forms control. Then I need to do something to make all WPF menus, etc. by DevExpress dismissed if they were open.
GlobalMouseHandler globalClick = new GlobalMouseHandler();
System.Windows.Forms.Application.AddMessageFilter( globalClick );
GlobalMouseHandler:
public class GlobalMouseHandler : System.Windows.Forms.IMessageFilter
{
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_RBUTTONDOWN = 0x204;
public bool PreFilterMessage( ref System.Windows.Forms.Message m )
{
if( m.Msg == WM_LBUTTONDOWN || m.Msg == WM_RBUTTONDOWN )
{
var c = System.Windows.Forms.Control.FromHandle( m.HWnd );
if( c != null )
// TODO: CLOSE ALL WPF MENUS ETC
// Didn't work: MainWindow.Instance.ARandomControl.Focus();
}
return false;
}
}
I made a prototype out of your issue and everything works (when I click inside Windows Form Host the outside WPF combox collapse and vice versa).
So we know the native controls works as expected, the problem might be because of the UI framework you are using.
https://documentation.devexpress.com/#wpf/DevExpressXpfBarsBarManager_CloseAllPopupstopic
So I had to:
MainWindow.Instance.BarManager.CloseAllPopups();
Did you try to loop through the controls and raise the lose focus event?

touch screen clear status message on any touch

Iam working on a touch screen windows form that has many checkboxes, textboxes, listboxes, date dropdown pickers etc. Depending on user action a status message is displayed at the bottom. For eg., Your profile saved successfully, From and to date cannot be same, Please select a valid ... etc
What is an elegant way to clear the status message on ANY touch.
if (statusLabel.text != string.empty )
statusLabel.text = string.empty)
Meaning if any checkbox is checked, any text is input in a textbox, any listbox or combo is selected...then I want to clear the status label. This way the last status message does not "stick" to confuse the user. I am poking around to see if I can override some event at the form level in one place that will do this.
thanks
thx Saravanan and Pedery for your suggestions. They do not solve my problem. I just discovered Reactive extensions and posting a related question which may help me. Left mouse button click detect on winform using Reactive extensions IObservable on events
Try to find an event in the statusbar itself like text changed or content changed etc. Override it to clear the content of itself.
You may write code to clear the status bar content on the change event of the control's container.
Its your choice.
You can put the message in the controls' Tag property and use a single common event to add them all up.
If you wanna be more orderly, you can subclass the checkbox with a custom property the same way.
This was the solution to my problem
protected override void WndProc(ref Message msg)
{
switch(msg.Msg)
{
case WM_LBUTTONDOWN:
//Do something here
break;
//add other cases if needed
}
// call the base class WndProc for default message handling
base.WndProc(ref msg);
}

Blocking the ability of being able to highlight text in a textbox in a C# windows form

I want to create a Windows form in C# with textbox whose text cannot be altered or selected by the user.
I managed to make it unalterable (ReadOnly = true), but I am still able to select and highlight the text.
How can I change this?
Thanks!
-R
This is the expected behavior and is by design. You can see this for yourself if you right-click on an item in Windows Explorer and open its Properties window. All of the dynamic text fields on the "General" tab are selectable, though not modifiable. If this is not the behavior you desire, you should strongly consider using a Label control instead. This is the exact situation for which it was intended—static text that is not selectable by the user.
In case, for whatever reason, you're not sold on why you should use a Label control instead, I'll proceed onward in answering the question you asked. The major problem with trying to override this behavior (like overriding the default behavior of any control) is that there are a lot of ways for the user to accomplish it: clicking and dragging with the mouse, double-clicking the mouse button, using the arrow keys on the keyboard in combination with the Shift key, tabbing into the textbox,right-clicking and choosing "Select All" from the context menu, etc...
Your first instinct might be to override the potentially relevant events exposed by the .NET Framework (such as OnMouseDown, OnKeyDown, etc.) and reset the selected length to 0 so that the text is immediately unselected after it is automatically selected. However, this causes a little bit of a flicker effect in the process, which may or may not be acceptable to you.
Alternatively, you could do the same thing by overriding the control's WndProc method, watching for the relevant window messages, and preventing the messages from being passed on to the control's base class altogether. This will prevent the flicker effect because the base TextBox control never actually receives a message causing it to automatically select its text, but it does have the obvious side effect of preventing the control from taking any action as a result of these common events. It seems like that probably doesn't matter to you in this case, but realize that this is still a pretty drastic hack. I definitely cannot recommend it as being good practice.
That being said, if you're still interested, you could use the following custom UnselectableTextBox class. It prevents the processing of every window message that I could think of which would possibly allow the user to select text. It does indeed work, but fair warning: there may be yet others I haven't thought of.
public class UnselectableTextBox : TextBox
{
public UnselectableTextBox() : base()
{
//Set it to read only by default
this.ReadOnly = true;
}
protected override void OnGotFocus(System.EventArgs e)
{
base.OnGotFocus(e);
//Prevent contents from being selected initally on focus
this.DeselectAll();
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_KEYDOWN = 0x100;
const int WM_LBUTTONDOWN = 0x201;
const int WM_LBUTTONDBLCLK = 0x203;
const int WM_RBUTTONDOWN = 0x204;
if ((m.Msg == WM_KEYDOWN) || (m.Msg == WM_LBUTTONDOWN) ||
(m.Msg == WM_LBUTTONDBLCLK) || (m.Msg == WM_RBUTTONDOWN))
{
this.DeselectAll();
return;
}
base.WndProc(ref m);
}
}
Use label inplace of textbox. I think you only want to show information but not to select, not to copy, using label will be better option...
Is disabling it an option? (Enabled = false)

Categories

Resources