locking winform location - c#

I have a main form window which will pop up a new form window. I want to lock the location of the popup form so that the window cannot be moved and it will move at the same time as the main form.
(so if a user drags the main form the popup moves with it)
Did a search on the site and some did it like this:
this.FormBorderStyle=System.Windows.Forms.FormBorderStyle.None
and I have the Locked attribute set to True but that doesn't work.
But I want to keep the borders. What's the proper way of locking a form?

public class Form1
{
private Form2 Form2 = new Form2();
private Point form2Location;
private Point form1Location;
private void Button1_Click(System.Object sender, System.EventArgs e)
{
form1Location = this.Location;
Form2.Show();
form2Location = Form2.Location;
}
private void Form1_Move(System.Object sender, System.EventArgs e)
{
Form2.IsMoving = true;
Point form2OffSetLocation = new Point(this.Location.X - form2Location.X, this.Location.Y - form2Location.Y);
Form2.Location = form2OffSetLocation;
Form2.IsMoving = false;
}
}
public class Form2
{
public bool IsMoving;
private void Form2_Move(System.Object sender, System.EventArgs e)
{
if (IsMoving) return;
if (staticLocation.X != 0 & staticLocation.Y != 0) this.Location = staticLocation;
}
private Point staticLocation;
private void Form2_Load(System.Object sender, System.EventArgs e)
{
staticLocation = this.Location;
}
}
I agree with Hans on this one and I think once you see how dodgy it looks you'll probably agree too.

You could do something like this (taken from here):
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);
}

Related

Sendkeys event is not detected inside the application in windows form application

I am new to windows app development. I am developing a Windows Form Application where the layout is as follows:
There is one textbox and i have created the keyboard inside the application using SendKeys event.
Problem is that all other application on the system are able to detect the keys but the textbox inside the application is not able to detect the keys.
Basically app is having complete keyboard this is just one button press code
What I have tried:
public partial class Form1 : Form
{
Control focusedC;
protected override CreateParams CreateParams
{
get
{
CreateParams param = base.CreateParams;
param.ExStyle |= 0x08000000;
return param;
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
TopMost = true;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape) {
FormBorderStyle = FormBorderStyle.Sizable;
WindowState = FormWindowState.Normal;
TopMost = false;
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
//checkbox is for CapsLock Key
}
private void button14_Click(object sender, EventArgs e)
{
if (checkBox1.Checked && focusedC != null)
{
focusedC.Focus();
SendKeys.Send("Q");
}
else if(focusedC != null)
{
focusedC.Focus();
SendKeys.Send("q");
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
focusedC = sender as TextBox;
}
}
Of cource it doesn't work on your window. You set the WS_EX_NOACTIVATE style! It works on other windows but not yours, obviously. If you want it to work on your textbox remove or comment this line
param.ExStyle |= 0x08000000;
and it will work fine in your app window not others:
private void button14_Click(object sender, EventArgs e)
{
if (checkBox1.Checked)
{
textBox1.Focus();
SendKeys.Send("Q");
}
else
{
textBox1.Focus();
SendKeys.Send("q");
}
}
For WPF applications, you have to use SendKeys.SendWait() method.
SendKeys.SendWait("Q")
SendKeys.Send() will work for WinForm Applications.
Another option is to use WinAPI instead of SendKeys. More information here
Edit 1
Control focusedC;
//Enter event handler for your TextBox
private void textBox1_TextChanged(object sender, EventArgs e)
{
focusedC = sender as TextBox;
}
//Click event handler
private void button14_Click(object sender, EventArgs e)
{
if (focusedC != null)
{
focusedC.Focus();
SendKeys.Send("Q");
}
}
Edit 2: Using WinAPI
[DllImport("user32.dll")]
static extern void SendInput(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void PressKey(byte keyCode)
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
SendInput((byte)keyCode, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
SendInput((byte)keyCode, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
Use by calling the PressKey function and Keycodes can be found here

ShowDialog with Parent still enabled

In one of our apps we want to want to limit the user from opening other menu items when an existing menu item is already open. We are currently doing this:
private void menuItem1_Click(object sender, EventArgs e)
{
Myform f = new MyForm();
f.ShowDialog(this);
}
However in doing this, we lose the ability to interact at all with the parent window because internally, the parent.enabled property was set to false. Using the code above, if the user has menu item open and wants to move the parent window to see something on their desktop, they first must close the menu item, move the parent, and reopen the menu item.
I have come up with the follow method of doing the UI in a backgroundworker
public class BaseForm : Form
{
private bool _HasChildOpen;
protected BackgroundWorker bgThead;
public BaseForm()
{
_HasChildOpen = false;
bgThead = new BackgroundWorker();
bgThead.DoWork += new DoWorkEventHandler(OpenChildWindow);
bgThead.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.ClearChildWindows);
}
protected void ClearChildWindows(object sender, RunWorkerCompletedEventArgs e)
{
_HasChildOpen = false;
}
public void OpenChildWindow(object sender, DoWorkEventArgs e)
{
if (!_HasChildOpen)
{
Form f = (Form)e.Argument;
f.StartPosition = FormStartPosition.CenterScreen;
f.ShowDialog();
}
}
}
and then each menu item has the following code
private void menuItem1_Click(object sender, EventArgs e)
{
if (!bgThead.IsBusy)
{
bgThead.RunWorkerAsync(new Myform());
}
}
but this approach is a big no no. However, using invoke seems to get me back where I started:
private void doUIWork(MethodInvoker d)
{
if (this.InvokeRequired)
{
this.Invoke(d);
}
else
{
d();
}
}
public void OpenChildWindow(object sender, DoWorkEventArgs e)
{
if (!_HasChildOpen)
{
doUIWork(delegate() {
Form f = (Form)e.Argument;
f.StartPosition = FormStartPosition.CenterScreen;
f.ShowDialog();
});
//Form f = (Form)e.Argument;
//f.StartPosition = FormStartPosition.CenterScreen;
//f.ShowDialog();
}
}
How do I properly limit the user to just one menu item open, but at the same time leave the parent enabled such that it can be moved resized etc?
You will need to programmatically disable menu strip behavior once one of the forms is open. So if you have Form1 and Form2, (with a menuStrip on Form1 and toolStripMenuItem1, toolStripMenuItem2 on the menuStrip):
private void menuItem1_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.FormClosing += f2_FormClosing;
f2.Show();
this.menuStrip1.Enabled = false;
}
private void menuItem2_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.FormClosing += f2_FormClosing;
f2.Show();
this.menuStrip1.Enabled = false;
}
void f2_FormClosing(object sender, FormClosingEventArgs e)
{
this.menuStrip1.Enabled = true;
}
using the Show() method instead of ShowDialog() enables interaction with the parent control, though you will need to manually disable/enable behavior depending on when the child control is shown or not.

form minimize on deactive - task bar button does not minimize

I have a form that that minimizes on deactivate but now the task bar button does not minimize the form. It goes away for an instance then comes back. There seems to be a race with the task bar function and the deactivate event where when I click the icon the form minimizes, then the task bar function sees that it is minimized and the form restores. I have the following code:
public Form1()
{
InitializeComponent();
Text = string.Empty;
ControlBox = false;
FormBorderStyle = FormBorderStyle.SizableToolWindow;
Deactivate += lostFocus;
}
private void lostFocus(object o, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
protected override void WndProc(ref Message message)
{
const int WM_NCHITTEST = 0x0084;
if (message.Msg == WM_NCHITTEST) return;
base.WndProc(ref message);
}
(Note that the form has no controls)
I was able to get it to kind of work with the following bandade:
private void focusTimerEvent(object o, EventArgs e)
{
WindowState = FormWindowState.Minimized;
focusTimer.Stop();
}
private void lostFocus(object o, EventArgs e)
{
focusTimer.Start();
}
and setting the timer to 1000 in Form1() method
focusTimer = new Timer();
focusTimer.Interval = 1000;
focusTimer.Tick += focusTimerEvent;
any suggestions would be appreciated

Is there an event raised in C# when a window is restored?

Is there any event that is raised when a window is restored in C#/.NET?
I noticed that there is an event that is raised when a window is activated, but I can't find a corresponding event for a window being restored, such as from a maximized or minimized state.
If you don't like using the form's WindowState property and don't want to have to keep around a flag indicating the form's previous state, you can achieve the same result at a slightly lower level.
You'll need to override your form's window procedure (WndProc) and listen for a WM_SYSCOMMAND message indicating SC_RESTORE. For example:
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_RESTORE = 0xF120;
if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_RESTORE)
{
// Do whatever processing you need here, or raise an event
// ...
MessageBox.Show("Window was restored");
}
base.WndProc(ref m);
}
You can check it this way:
private void Form1_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
...
}
else if ....
{
}
}
Pretty unsure. You'd have to handle the SizeChanged event and detect if WindowState changed from Minimized to Normal or Maximized to Normal. Source
I know this question is quite old but it works this way:
public Form1()
{
InitializeComponent();
this.SizeChanged += new EventHandler(Form1_WindowStateTrigger);
}
private void Form1_WindowStateTrigger(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
MessageBox.Show("FORM1 MINIMIZED!");
}
if (this.WindowState == FormWindowState.Normal)
{
MessageBox.Show("FORM1 RESTORED!");
}
if (this.WindowState == FormWindowState.Maximized)
{
MessageBox.Show("FORM1 MAXIMIZED!");
}
}
Using the SizeChanged event, coupled with a check of WindowState does the trick here.
Check:
private void Form1_Activated(Object o, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized) {
...
}
}
The answer from Redhart is good. This is the same but slightly simpler:
public Form1()
{
InitializeComponent();
this.SizeChanged += Form1_SizeChanged;
}
#region Event-Handlers
void Form1_SizeChanged(object sender, EventArgs e)
{
var state = this.WindowState;
switch (state)
{
case FormWindowState.Maximized:
ClearMyView();
DisplayMyStuff();
break;
case FormWindowState.Minimized:
break;
case FormWindowState.Normal:
ClearMyView();
DisplayMyStuff();
break;
default:
break;
}
}
#endregion Event-Handlers
It's easy enough to add:
public partial class Form1 : Form {
private FormWindowState mLastState;
public Form1() {
InitializeComponent();
mLastState = this.WindowState;
}
protected override void OnClientSizeChanged(EventArgs e) {
if (this.WindowState != mLastState) {
mLastState = this.WindowState;
OnWindowStateChanged(e);
}
base.OnClientSizeChanged(e);
}
protected void OnWindowStateChanged(EventArgs e) {
// Do your stuff
}
go to this link
winforms-windowstate-changed-how-to-detect-this?

Make a borderless form movable?

Is there a way to make a form that has no border (FormBorderStyle is set to "none") movable when the mouse is clicked down on the form just as if there was a border?
This article on CodeProject details a technique. Is basically boils down to:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
This essentially does exactly the same as grabbing the title bar of a window, from the window manager's point of view.
Let's not make things any more difficult than they need to be. I've come across so many snippets of code that allow you to drag a form around (or another Control). And many of them have their own drawbacks/side effects. Especially those ones where they trick Windows into thinking that a Control on a form is the actual form.
That being said, here is my snippet. I use it all the time. I'd also like to note that you should not use this.Invalidate(); as others like to do because it causes the form to flicker in some cases. And in some cases so does this.Refresh. Using this.Update, I have not had any flickering issues:
private bool mouseDown;
private Point lastLocation;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
lastLocation = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if(mouseDown)
{
this.Location = new Point(
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
this.Update();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
Another simpler way to do the same thing.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// set this.FormBorderStyle to None here if needed
// if set to none, make sure you have a way to close the form!
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
m.Result = (IntPtr)(HT_CAPTION);
}
private const int WM_NCHITTEST = 0x84;
private const int HT_CLIENT = 0x1;
private const int HT_CAPTION = 0x2;
}
use MouseDown, MouseMove and MouseUp. You can set a variable flag for that. I have a sample, but I think you need to revise.
I am coding the mouse action to a panel. Once you click the panel, your form will move with it.
//Global variables;
private bool _dragging = false;
private Point _offset;
private Point _start_point=new Point(0,0);
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
_dragging = true; // _dragging is your variable flag
_start_point = new Point(e.X, e.Y);
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
_dragging = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if(_dragging)
{
Point p = PointToScreen(e.Location);
Location = new Point(p.X - this._start_point.X,p.Y - this._start_point.Y);
}
}
WPF only
don't have the exact code to hand, but in a recent project I think I used MouseDown event and simply put this:
frmBorderless.DragMove();
Window.DragMove Method (MSDN)
It worked for Me.
private Point _mouseLoc;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
_mouseLoc = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.Location.X - _mouseLoc.X;
int dy = e.Location.Y - _mouseLoc.Y;
this.Location = new Point(this.Location.X + dx, this.Location.Y + dy);
}
}
Ref. video Link
This is tested and easy to understand.
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x84:
base.WndProc(ref m);
if((int)m.Result == 0x1)
m.Result = (IntPtr)0x2;
return;
}
base.WndProc(ref m);
}
Since some answers do not allow for child controls to be draggable, I've created a little helper class.
It should be passed the top level form. Can be made more generic if desired.
class MouseDragger
{
private readonly Form _form;
private Point _mouseDown;
protected void OnMouseDown(object sender, MouseEventArgs e)
{
_mouseDown = e.Location;
}
protected void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.Location.X - _mouseDown.X;
int dy = e.Location.Y - _mouseDown.Y;
_form.Location = new Point(_form.Location.X + dx, _form.Location.Y + dy);
}
}
public MouseDragger(Form form)
{
_form = form;
MakeDraggable(_form);
}
private void MakeDraggable(Control control)
{
var type = control.GetType();
if (typeof(Button).IsAssignableFrom(type))
{
return;
}
control.MouseDown += OnMouseDown;
control.MouseMove += OnMouseMove;
foreach (Control child in control.Controls)
{
MakeDraggable(child);
}
}
}
There's no property you can flip to make this just happen magically. Look at the events for the form and it becomes fairly trivial to implement this by setting this.Top and this.Left. Specifically you'll want to look at MouseDown, MouseUp and MouseMove.
public Point mouseLocation;
private void frmInstallDevice_MouseDown(object sender, MouseEventArgs e)
{
mouseLocation = new Point(-e.X, -e.Y);
}
private void frmInstallDevice_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point mousePos = Control.MousePosition;
mousePos.Offset(mouseLocation.X, mouseLocation.Y);
Location = mousePos;
}
}
this can solve ur problem....
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d803d869-68e6-46ff-9ff1-fabf78d6393c/how-to-make-a-borderless-form-in-c?forum=csharpgeneral
This bit of code from the above link did the trick in my case :)
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
this.Capture = false;
Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
this.WndProc(ref msg);
}
}
Best way I've found (modified of course)
// This adds the event handler for the control
private void AddDrag(Control Control) { Control.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DragForm_MouseDown); }
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
private void DragForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Checks if Y = 0, if so maximize the form
if (this.Location.Y == 0) { this.WindowState = FormWindowState.Maximized; }
}
}
To apply drag to a control simply insert this after InitializeComponent()
AddDrag(NameOfControl);
For .NET Framework 4,
You can use this.DragMove() for the MouseDown event of the component (mainLayout in this example) you are using to drag.
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Easiest way is:
First create a label named label1.
Go to label1's events > mouse events > Label1_Mouse Move and write these:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
I was trying to make a borderless windows form movable which contained a WPF Element Host control and a WPF User control.
I ended up with a stack panel called StackPanel in my WPF user control which seemed the logical thing to try click on to move. Trying junmats's code worked when I moved the mouse slowly, but if I moved the mouse faster, the mouse would move off the form and the form would be stuck somewhere mid move.
This improved on his answer for my situation using CaptureMouse and ReleaseCaptureMouse and now the mouse does not move off the form while moving it even if I move it quickly.
private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
{
_start_point = e.GetPosition(this);
StackPanel.CaptureMouse();
}
private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
StackPanel.ReleaseMouseCapture();
}
private void StackPanel_MouseMove(object sender, MouseEventArgs e)
{
if (StackPanel.IsMouseCaptured)
{
var p = _form.GetMousePositionWindowsForms();
_form.Location = new System.Drawing.Point((int)(p.X - this._start_point.X), (int)(p.Y - this._start_point.Y));
}
}
//Global variables;
private Point _start_point = new Point(0, 0);
I'm expanding the solution from jay_t55 with one more method ToolStrip1_MouseLeave that handles the event of the mouse moving quickly and leaving the region.
private bool mouseDown;
private Point lastLocation;
private void ToolStrip1_MouseDown(object sender, MouseEventArgs e) {
mouseDown = true;
lastLocation = e.Location;
}
private void ToolStrip1_MouseMove(object sender, MouseEventArgs e) {
if (mouseDown) {
this.Location = new Point(
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
this.Update();
}
}
private void ToolStrip1_MouseUp(object sender, MouseEventArgs e) {
mouseDown = false;
}
private void ToolStrip1_MouseLeave(object sender, EventArgs e) {
mouseDown = false;
}
Also if you need to DoubleClick and make your Form bigger/smaller , you can use the First answer, create a global int variable, add 1 every time user clicks on the component you use for dragging. If variable == 2 then make your form bigger/smaller. Also use a timer for every half a sec or a second to make your variable = 0;
Adding a MouseLeftButtonDown event handler to the MainWindow worked for me.
In the event function that gets automatically generated, add the below code:
base.OnMouseLeftButtonDown(e);
this.DragMove();
Form1(): new Moveable(control1, control2, control3);
Class:
using System;
using System.Windows.Forms;
class Moveable
{
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
public Moveable(params Control[] controls)
{
foreach (var ctrl in controls)
{
ctrl.MouseDown += (s, e) =>
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(ctrl.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Checks if Y = 0, if so maximize the form
if (ctrl.FindForm().Location.Y == 0) { ctrl.FindForm().WindowState = FormWindowState.Maximized; }
}
};
}
}
}
I tried the following and presto changeo, my transparent window was no longer frozen in place but could be moved!! (throw away all those other complex solutions above...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}

Categories