Handling release key in custom panel control - c#

I have custom control derived from Panel and I need to handle selecting with mouse. I found that for panel I must override ProcessCmdKey and it is working for pressing keys but what if I want to handle when control key is release? Thanks

Perhaps this can help you:
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
protected override bool ProcessKeyPreview(ref Message m)
{
if (m.Msg == WM_KEYDOWN && (Keys)m.WParam == Keys.ControlKey)
{
//Do something
}
else if (m.Msg == WM_KEYUP && (Keys)m.WParam == Keys.ControlKey)
{
//Do something
}
return base.ProcessKeyPreview(ref m);
}
And you could take a look at this (If you haven't already): http://support.microsoft.com/kb/320584

Related

Smooth scrolling FlowLayoutPanel C#

Could any one help me solve this problem.
I have FlowLayoutPanel and in it I have multiple UserControls.
Have enabled auto scrolling.
Problem I have is UserControls are flickering/blinking on scrolling. I understand this is because OnPaint event. I have tried folowing code. Have derivated from FlowLayoutControl and trying to override WndProc but without success.
class ScrollFlowLayoutPanel : FlowLayoutPanel
{
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
protected override void WndProc(ref Message m)
{
if ((m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL) && (((int)m.WParam & 0xFFFF) == 5))
{
// Change SB_THUMBTRACK SB_THUMBPOSITION
m.WParam = (IntPtr)(((int)m.WParam & ~0xFFFF) | 4);
}
base.WndProc (ref m);
}
}
Thanks

Hold Arrow Key Down Event with ProcessCmdKey

I need to perform a certain method as long as an arrow key is being held down. Now, for regular arrow key presses in Visual studio 2012, using OnKeyDown did not work, so I needed to use ProcessCmdKey, which works like a charm. Is there a way to use ProcessCmdKey to detect when an arrow has been released / being held down?
I've taken both Markus' and Hans' advice, and combined the two ideas. I used the ProcessKeyPreview method, but I am still having some issues. When I hold down any arrow key, this method will not detect that WM_KEYDOWN has happened... but as soon as I release my finger from the key, it actually DOES notice that WM_KEYUP has happened.
The interesting this is that when I hold down any other key (i.e. letter 'S'), it properly recognizes when it has been pressed and released. I've posted a fragment of my code below:
const int WM_KEYUP = 0x0101;
const int WM_KEYDOWN = 0x0100;
protected override bool ProcessKeyPreview(ref Message m)
{
int msgVal = m.WParam.ToInt32();
if (m.Msg == WM_KEYDOWN)
{
switch ((Keys)msgVal) {
case Keys.Down:
Console.WriteLine("down pressed"); //not detected
break;
case Keys.S:
Console.WriteLine("S pressed!"); //detected
break;
}
}
if (m.Msg == WM_KEYUP)
{
switch ((Keys)msgVal)
{
case Keys.Down:
Console.WriteLine("down released"); //detected
break;
case Keys.S:
Console.WriteLine("s released!"); //detected
break;
}
}
return base.ProcessKeyPreview(ref m);
}
You cannot see the KeyUp event with ProcessCmdKey(), it was made to only handle KeyDown events. You'll need to tackle this at a much lower level if the form contains controls. The trick is to intercept the message before Winforms sends it through the normal key-handling and WndProc chain. That requires implementing the IMessageFilter interface. Like this:
public partial class Form1 : Form, IMessageFilter { // NOTE: added IMessageFilter
public Form1() {
InitializeComponent();
Application.AddMessageFilter(this);
}
protected override void OnFormClosed(FormClosedEventArgs e) {
Application.RemoveMessageFilter(this);
base.OnFormClosed(e);
}
bool IMessageFilter.PreFilterMessage(ref Message m) {
// Trap WM_KEYUP/DOWN for Keys.Down key
if ((m.Msg == 0x100 || m.Msg == 0x101) && (Keys)m.WParam.ToInt32() == Keys.Down) {
bool repeat = (m.LParam.ToInt32() & (1 << 30)) != 0;
bool down = m.Msg == 0x100;
// But only for this form
Form form = null;
var ctl = Control.FromHandle(m.HWnd);
if (ctl != null) form = ctl.FindForm();
if (form == this) {
OnCursorDown(down, repeat & down);
return true;
}
}
return false;
}
private void OnCursorDown(bool pressed, bool repeat) {
// etc..
}
}
You can overload ProcessKeyPreview instead, which will let you see the WM_KEYDOWN message as well as the WM_KEYUP message. Be sure to turn on KeyPreview for the form.
WM_KEYDOWN:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646280(v=vs.85).aspx
WM_KEYUP:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646281(v=vs.85).aspx
Example:
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
this.KeyPreview = true;
}
const int WM_KEYUP = 0x0101;
const int WM_KEYDOWN = 0x0100;
protected override bool ProcessKeyPreview(ref Message m)
{
switch (m.Msg)
{
case WM_KEYDOWN:
Console.WriteLine(m.LParam);
break;
case WM_KEYUP:
Console.WriteLine(m.LParam);
break;
}
return base.ProcessKeyPreview(ref m);
}
}

Is it possible to make a C# form non movable [duplicate]

How would i go about stopping a form from being moved. I have the form border style set as FixedSingle and would like to keep it this way because it looks good in vista :)
Take a look at this link. You might be interested in option #3. It will require you to wrap some native code, but should work. There's also a comment at the bottom of the link that shows an easier way to do it. Taken from the comment (can't take credit for it, but I'll save you some searching):
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
switch(message.Msg)
{
case WM_SYSCOMMAND:
int command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
return;
break;
}
base.WndProc(ref message);
}
You can set the FormBorderStyle property of the Form to None
this.FormBorderStyle=System.Windows.Forms.FormBorderStyle.None
I found this to stop the form from moving (its in c#)
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
switch (m.Msg)
{
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
return;
break;
}
base.WndProc(ref m);
}
Found here
Try to override WndProc:
protected override void WndProc(ref Message m)
{
const int WM_NCLBUTTONDOWN = 161;
const int WM_SYSCOMMAND = 274;
const int HTCAPTION = 2;
const int SC_MOVE = 61456;
if ((m.Msg == WM_SYSCOMMAND) && (m.WParam.ToInt32() == SC_MOVE))
{
return;
}
if ((m.Msg == WM_NCLBUTTONDOWN) && (m.WParam.ToInt32() == HTCAPTION))
{
return;
}
base.WndProc(ref m);
}
It's not all pretty (there is some flashing going on when you try to move the form), but you can use the LocationChanged property to keep the form where you want it:
private Point _desiredLocation;
// assign the _desiredLocation variable with the form location at some
// point in the code where you know that the form is in the "correct" position
private void Form_LocationChanged(object sender, EventArgs e)
{
if (this.Location != _desiredLocation)
{
this.Location = _desiredLocation;
}
}
Out of curiousity; why would you want to do this?
In Windows, the WS_CAPTION style is the non-client area that allows your window to be moved with a mouse. So the easiest way to do what you want is to remove this style from your window.
However, if you need to have a caption and still achieve what you want, then the next style would be to capture the WM_NCHITTEST message and check for HTCAPTION. If the code is HTCAPTION, return NTNOWHERE instead. This will prevent the default window procedure from executing the default move window thing.
It's not a good practice to make your form immovable. I'd think agfain about it if I were you.
Anyway, you can do this by overridding the WinProc to disable the [Move] menuitem from the system menu.
[DllImport("user32.dll")]
private static extern Int32 EnableMenuItem ( System.IntPtr hMenu , Int32uIDEnableItem, Int32 uEnable);
private const Int32 HTCAPTION = 0×00000002;
private const Int32 MF_BYCOMMAND =0×00000000;
private const Int32 MF_ENABLED =0×00000000;
private const Int32 MF_GRAYED =0×00000001;
private const Int32 MF_DISABLED =0×00000002;
private const Int32 SC_MOVE = 0xF010;
private const Int32 WM_NCLBUTTONDOWN = 0xA1;
private const Int32 WM_SYSCOMMAND = 0×112;
private const Int32 WM_INITMENUPOPUP = 0×117;
protected override void WndProc(ref System.Windows.Forms.Message m )
{
if (m.Msg == WM_INITMENUPOPUP)
{
//handles popup of system menu
if ((m.LParam.ToInt32() / 65536) != 0) // 'divide by 65536 to get hiword
{
Int32 AbleFlags = MF_ENABLED;
if (!Moveable)
{
AbleFlags = MF_DISABLED | MF_GRAYED; // disable the move
}
EnableMenuItem(m.WParam, SC_MOVE, MF_BYCOMMAND | AbleFlags);
}
}
if (!Moveable)
{
if (m.Msg == WM_NCLBUTTONDOWN) //cancels the drag this is IMP
{
if (m.WParam.ToInt32() == HTCAPTION) return;
}
if (m.Msg == WM_SYSCOMMAND) // Cancels any clicks on move menu
{
if ((m.WParam.ToInt32() & 0xFFF0) == SC_MOVE) return;
}
}
base.WndProc(ref m);
}
Also, you can handle OnMove event of your form. But I think this will cause some flickering:
private void Form1_Move(object sender, EventArgs e)
{
this.Location = defaultLocation;
}
Just change the FormBorderStyle property to None.
change the Form property StartPostion to Manual.
Then, handle the LocationChanged event:
private void frmMain_LocationChanged(object sender, EventArgs e)
{
Location = new Point(0, 0);
}
Go to form events-> Location changed
write the following code
Location = new Point(this.Width,this.Height);
I would question your need to make the form unmovable. This doesn't sound nice. You could of course save the location of the window when the window closes and reopen the window into that position. That gives the user some control over where the window should be located.
You can subscribe to the Form.Move event and reposition from it.
Just reset the location on formlocation_changed event to where it was i.e. set the Form.Location to a variable before it's moved and when the user tries to move it, it will go back to the variable location you set it to.
Private Sub MyFormLock()
Me.Location = New Point(0, 0)
End Sub
Private Sub SearchSDR_LocationChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LocationChanged
Call MyFormLock()
End Sub
You can try:
this.Locked = true;

unselectable node in TreeView

I have TreeView control on winform. I desire to make several nodes unselectable. How can I achive this.
There is only one idea in my mind - custom drawn nodes, but may be more easier way exists? Please advice me
I have already try such code in BeforeSelect event handler:
private void treeViewServers_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
if (e.Node.Parent != null)
{
e.Cancel = true;
}
}
But effect it gained is not appropriate. Node temporary get selection when I am holding left mouse button on it.
Thanks in advance!
You could completely disable mouse events in case you click on a not-selectable node.
To do this, you have to override TreeView a shown in the following code
public class MyTreeView : TreeView
{
int WM_LBUTTONDOWN = 0x0201; //513
int WM_LBUTTONUP = 0x0202; //514
int WM_LBUTTONDBLCLK = 0x0203; //515
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN ||
m.Msg == WM_LBUTTONUP ||
m.Msg == WM_LBUTTONDBLCLK)
{
//Get cursor position(in client coordinates)
Int16 x = (Int16)m.LParam;
Int16 y = (Int16)((int)m.LParam >> 16);
// get infos about the location that will be clicked
var info = this.HitTest(x, y);
// if the location is a node
if (info.Node != null)
{
// if is not a root disable any click event
if(info.Node.Parent != null)
return;//Dont dispatch message
}
}
//Dispatch as usual
base.WndProc(ref m);
}
}

How to avoid flickering in treeview

how to avoid flickering in treeview,
when some property of nodes is gettng updated,
or the node is added
Try the following:
try
{
treeView.BeginUpdate();
// Update your tree view.
}
finally
{
treeView.EndUpdate();
}
I was fighting this, too. Here is my solution for those of you searching out there. Add this to your treeview subclass.
private const int WM_VSCROLL = 0x0115;
private const int WM_HSCROLL = 0x0114;
private const int SB_THUMBTRACK = 5;
private const int SB_ENDSCROLL = 8;
private const int skipMsgCount = 5;
private int currentMsgCount;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_VSCROLL || m.Msg == WM_HSCROLL)
{
var nfy = m.WParam.ToInt32() & 0xFFFF;
if (nfy == SB_THUMBTRACK)
{
currentMsgCount++;
if (currentMsgCount % skipMsgCount == 0)
base.WndProc(ref m);
return;
}
if (nfy == SB_ENDSCROLL)
currentMsgCount = 0;
base.WndProc(ref m);
}
else
base.WndProc(ref m);
}
I got the idea here: treeview scrollbar event
Basically I am just ignoring a significant percentage of the scroll messages. It reduces flicker a lot for me.

Categories

Resources