Form doesn't have DragMove() method? - c#

So I need to move my form no matter what element is clicked (I need to drag form by pressing and holding button, form is 100% transparent) , I tried to do this:
private void MessageForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
this.DragMove();
}
but I was quite surprised that there in no DragMove() method, it was renamed or what I am missing?
And if this is not possible, is there any other way to do that?

You will need something like this:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
private void MessageForm_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
Basically, it acts like dragging the title bar/window caption when you drag anywhere in the window. This is great for borderless windows.
EDIT:
If you use a button as the control for moving the form, you will need to be careful when attaching your click event handler as you are overriding the Windows Forms event loop for that control.
By moving/adding the ReleaseCapture and SendMessage calls to the MouseDown event of a control, you can use it to drag the window. Any control can be used to drag the window as long as you update the MouseDown event to be similar to the code above.

Tested and working: this.DragMove(), alternative
private void Form1_Load(object sender, EventArgs e)
{
FormCommonSetting(this);
}
public void FromCommonSetting(Form _Form)
{
_Form.StartPosition = FormStartPosition.CenterScreen;
_Form.FormBorderStyle = FormBorderStyle.None;
_Form.MaximizeBox = false;
_Form.ShowInTaskbar = true;
_Form.AutoSize = false;
}
protected override void WndProc(ref Message _Message)
{
switch (_Message.Msg)
{
case 0x84:
base.WndProc(ref _Message);
if ((int)_Message.Result == 0x1)
_Message.Result = (IntPtr)0x2;
return;
}
base.WndProc(ref _Message);
}

Related

how do I bind the repeating codes shared by multiple forms in c#

I have around 10+ child forms and all the child forms have the following features
Close button: on hover displays "close" text and when mouse clicked, shows a message box to confirm the action
Minimize button: On hover, it displays "minimize" text, when the mouse is clicked, the form gets minimized
Drag anyway inside the parent form
I have to avoid using Visual Studio's default style to get a desirable customized form.
-The code below is shared by all the child forms, since the code is the same, is there a way to bind to one place and reference?
code
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HTCAPTION = 0x2;
[DllImport("User32.dll")]
public static extern bool ReleaseCapture();
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
//Dtrag the form
private void DragPanel(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
}
#region controlbox
private void minimizebtn_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
private void closebtn_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure you want to Close the window?", "Close", MessageBoxButtons.OKCancel) == DialogResult.OK)
{
Close();
//Application.Exit();
}
}
private void closebtn_MouseHover(object sender, EventArgs e)
{
System.Windows.Forms.ToolTip ToolTip1 = new System.Windows.Forms.ToolTip();
ToolTip1.SetToolTip(this.closebtn, "Close");
}
private void minimizebtn_MouseHover(object sender, EventArgs e)
{
System.Windows.Forms.ToolTip ToolTip1 = new System.Windows.Forms.ToolTip();
ToolTip1.SetToolTip(this.minimizebtn, "Minimize");
}
#endregion
You could create a base class which itself derives from Form. Your actual forms should then derive from that base class.

How to distinguish whether Enter event was raised by keyboard or mouse click?

Is there a way to distinguish whether the Enter event on a control was raised by keyboard (Tab, Shift+Tab) or by direct mouse click?
I need to perform an action only when the user is moving to the control using Tab, but not when the user directly clicks on the control. I have tried to intercept the mouse click directly, but it seems the Enter event is raised before Click.
Instead of tracking the Tab key, you can use the WM_MOUSEACTIVATE message to detect activation of the control with the mouse. You could either sub-class each control type you use and override the WndProc method or use a NativeWindow listener class like the one presented below. Depending on how many types of controls you use, it may be less work and clutter to just sub-class those controls to provide a property that indicates that the control was selected using the mouse. It is your decision to make, but the pattern will be the same.
This code is a slight modification of the example shown in the MS documentation.
public class MouseActivateListener : NativeWindow
{
private Control parent;
public MouseActivateListener(Control parent)
{
parent.HandleCreated += this.OnHandleCreated;
parent.HandleDestroyed += this.OnHandleDestroyed;
parent.Leave += Parent_Leave;
this.parent = parent;
if (parent.IsHandleCreated)
{
AssignHandle(parent.Handle);
}
}
private void Parent_Leave(object sender, EventArgs e)
{
MouseActivated = false;
}
private void OnHandleCreated(object sender, EventArgs e)
{
AssignHandle(((Form)sender).Handle);
}
private void OnHandleDestroyed(object sender, EventArgs e)
{
ReleaseHandle();
}
public bool MouseActivated { get; set; }
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
const Int32 WM_MouseActivate = 0x21;
base.WndProc(ref m);
if (m.Msg == WM_MouseActivate && m.Result.ToInt32() < 3)
{
MouseActivated = true;
}
}
}
Example Usage:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MouseActivateListener textBox1Listener;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
textBox1Listener = new MouseActivateListener(textBox1);
}
private void textBox1_Enter(object sender, EventArgs e)
{
if (textBox1Listener.MouseActivated)
{
MessageBox.Show("Mouse Enter");
}
else
{
MessageBox.Show("Tab Enter");
}
}
}
You can use the Form.KeyPreview event and store the last key press in a variable. Then in your control's Enter event, check the value of the key that was pressed last. If this is a tab, do whatever you need to:
private Keys lastKeyCode;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
this.lastKeyCode = e.KeyCode;
}
Then in the Enter event, check it:
if (lastKeyCode == Keys.Tab)
{
// Whatever...
}
Intercepting WM_KEYUP and WM_KEYDOWN directly with a message filter to retrieve the state of the Tab key worked. This seems excessive for such a seemingly straightforward task, but apparently the Tab key is suppressed from most windows forms events.
Would be happy to take a cleaner answer, but for now, this is it:
class TabMessageFilter : IMessageFilter
{
public bool TabState { get; set; }
public bool PreFilterMessage(ref Message m)
{
const int WM_KEYUP = 0x101;
const int WM_KEYDOWN = 0x100;
switch (m.Msg)
{
case WM_KEYDOWN:
if ((Keys)m.WParam == Keys.Tab) TabState = true;
break;
case WM_KEYUP:
if ((Keys)m.WParam == Keys.Tab) TabState = false;
break;
}
return false;
}
}
class MainForm : Form
{
TabMessageFilter tabFilter;
public MainForm()
{
tabFilter = new TabMessageFilter();
Application.AddMessageFilter(tabFilter);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
Application.RemoveMessageFilter(tabFilter);
base.OnFormClosed(e);
}
void control_Enter(object sender, EventArgs e)
{
if (tabFilter.TabState) // do something
else // do domething else
}
}

Add click event everywhere on a winform except for a specific panel

I was looking for an answer and found an almost complete one by #LarsTech but without the exception :
https://stackoverflow.com/a/21314496/7026554
//You can still use MessageFilter and just filter for the ActiveForm:
private class MouseDownFilter : IMessageFilter {
public event EventHandler FormClicked;
private int WM_LBUTTONDOWN = 0x201;
private Form form = null;
[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);
public MouseDownFilter(Form f) {
form = f;
}
public bool PreFilterMessage(ref Message m) {
if (m.Msg == WM_LBUTTONDOWN) {
if (Form.ActiveForm != null && Form.ActiveForm.Equals(form)) {
OnFormClicked();
}
}
return false;
}
protected void OnFormClicked() {
if (FormClicked != null) {
FormClicked(form, EventArgs.Empty);
}
}
}
//Then in your form, attach it:
public Form1() {
InitializeComponent();
MouseDownFilter mouseFilter = new MouseDownFilter(this);
mouseFilter.FormClicked += mouseFilter_FormClicked;
Application.AddMessageFilter(mouseFilter);
}
void mouseFilter_FormClicked(object sender, EventArgs e) {
// do something...
}
What I want is to hide the notifications panel but not when clicking on its content or the profile picture that shows it.
I have a procedure called NotificationVisible(bool IsVisible)
Any help is greatly appreciated.
So your mouseFilter_FormClicked fires whenever user clickes on form. Now the only thing you need to do is to detect the control that is placed behind the mouse cursor and with that you can deside whether you need to hide your panel or not.
You can do this with WindowFromPoint method. Check this thread.
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pnt);
void mouseFilter_FormClicked(object sender, EventArgs e) {
IntPtr hWnd = WindowFromPoint(Control.MousePosition);
if (hWnd != IntPtr.Zero) {
Control ctl = Control.FromHandle(hWnd);
if (ctl != YourPanelControl) {
HideThePanel();
}
}
}

C# check characters in clipboard when paste into textbox

Are there some ways to check charater in clipboard only digit before paste into textbox C# (Both Ctrl+V and right click -> Paste), which not using MarkedTextbox.
Add rule in textbox text change to accept number only like:
private string value;
private void textBox1_TextChanged(object sender, EventArgs e)
{
// at this moment value is still old
var oldValue = value;
if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
{
MessageBox.Show("Please enter numbers only.");
textBox1.Text = oldvalue;
}
else{
value = ((TextBox)sender).Text;
}
}
I ~think~ you want a TextBox that can only accept digits?
If yes, then set the ES_NUMBER style on the TextBox via SetWindowLong():
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += Form2_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
SetNumbersOnlyTextBox(this.textBox1);
}
public const int GWL_STYLE = (-16);
public const int ES_NUMBER = 0x2000;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
public void SetNumbersOnlyTextBox(TextBox TB)
{
SetWindowLong(TB.Handle, GWL_STYLE, GetWindowLong(TB.Handle, GWL_STYLE) | ES_NUMBER);
}
}
Alternatively, you can Inherit from TextBox and set ES_NUMBER in CreateParams():
public class IntegerTextBox : TextBox
{
private const int ES_NUMBER = 0x2000;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style = cp.Style | ES_NUMBER;
return cp;
}
}
}
I doubt there are anyways to check before pasting to TextBox, I would suggest subscribing to KeyDown and MouseClick events, and writing your own logic.
protected override void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.V && e.Modifiers == Keys.Control)
{
// Your logic to read clipboard content and check length.;
}
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
// You logic goes here.
}
}
You can get help from MSDN on how to read/write clipboard content.
If you literally want to only allow pastes that have digits only, then Inherit from TextBox and trap WM_PASTE, suppressing the message when desired:
public class DigitsOnlyOnPasteTextBox : TextBox
{
private const int WM_PASTE = 0x302;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE && Clipboard.ContainsText())
{
int i;
string txt = Clipboard.GetText();
foreach(char c in txt)
{
if (!char.IsNumber(c))
{
return;// suppress default behavior
}
}
}
base.WndProc(ref m); // allow normal processing of the message
}
}

LocationChanged is not reliably called when Window is being dragged

To implement docking I was relying on listening to the Window.LocationChanged event to detect the changing position of a window being dragged around the screen. But a user reported that docking was not working on their machine.
Turns out they had disabled "Show window contents while dragging" in Windows performance options and as a result the LocationChanged event is only fired once the window is moved to it's final position, not while the window is in mid-flight.
I was wondering if there was an alternative way to detect window moves, a nice way. I know I could pinvoke, or wire up some horrific timer, but I was hoping for a better way, perhaps there is a reliable event to listen on?
Here's a method to forestall any "you didn't post any code"/"what have you tried" complaints.
protected override void OnLocationChanged(EventArgs e)
{
}
Here's my solution,
Excellent work.
class MyWindow : Window
{
private const int WM_MOVING = 0x0216;
private HwndSource _hwndSrc;
private HwndSourceHook _hwndSrcHook;
public MyWindow()
{
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
void OnUnloaded(object sender, RoutedEventArgs e)
{
_hwndSrc.RemoveHook(_hwndSrcHook);
_hwndSrc.Dispose();
_hwndSrc = null;
}
void OnLoaded(object sender, RoutedEventArgs e)
{
_hwndSrc = HwndSource.FromDependencyObject(this) as HwndSource;
_hwndSrcHook = FilterMessage;
_hwndSrc.AddHook(_hwndSrcHook);
}
private IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_MOVING:
OnLocationChange();
break;
}
return IntPtr.Zero;
}
private void OnLocationChange()
{
//Do something
}
}

Categories

Resources