Is there a way to disable the exit button on a windows form without having to import the some external .dll's? I disable the exit button by importing dll's using the following code but I don't like it. Is there a simpler (built-in) way?
public Form1()
{
InitializeComponent();
hMenu = GetSystemMenu(this.Handle, false);
}
private const uint SC_CLOSE = 0xf060;
private const uint MF_GRAYED = 0x01;
private IntPtr hMenu;
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
private static extern int EnableMenuItem(IntPtr hMenu, uint wIDEnableItem, uint wEnable);
// handle the form's Paint and Resize events
private void Form1_Paint(object sender, PaintEventArgs e)
{
EnableMenuItem(hMenu, SC_CLOSE, MF_GRAYED);
}
private void Form1_Resize(object sender, EventArgs e)
{
EnableMenuItem(hMenu, SC_CLOSE, MF_GRAYED);
}
You can't easily disable the exit button (the one in the top right that closes the form).
You can, however, hide the button completely, by setting the ControlBox property to false.
ControlBox can be turned on and off at any time, so you can use this if you want to dynamically allow closing at some times, and not at others.
Alternatively, you can handle the FormClosing event and cancel the close if you choose.
Here's a demo.
Create a new Windows Forms project.
Drop a CheckBox control on the form, with Text "ControlBox". Hook up its Click event to this:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
ControlBox = checkBox1.Checked;
}
Then, drop a second CheckBox control on the form with Text "Cancel Close". Hook up the FormClosing event of the form to this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = checkBox2.Checked;
}
Run the application and start playing around with the checkboxes. You'll soon see how things work.
To disable the close button on the form just write the below code on the form closing event.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
A little poking around found this handy helper class:
Disable Close Button and Prevent Form Being Moved (C# version)
It actually does more than what you're looking for, but essentially does it very nearly the same way you do in your sample code. The helper class hooks into the load/resize events for you so you don't have to remember to do it yourself.
Yes.
Setting the form.ControlBox = false will hide the close button. Although, it will also hide the minimize and maximize button.
You can also set form.FormBorderStyle = FormBorderStyle.None, which will hide the whole title bar.
If you want to show the X button but just stop the form from closing, override OnClosing and set the e.Cancel property to true.
Catch the FormClosing event and cancel it in the arguments.
Using visual studio select the form go to the properties and set the ControlBox property to false or try this.ControlBox = false; or frmMainForm.ControlBox = false;
Disabling the button is possible without importing dlls. ControlBox = false causes minimise and maximise buttons and the border to disappear as well and it does not disable the close 'X' button - it hides. This solution disables it:
private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams
{
get
{
CreateParams myCp = base.CreateParams;
myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON ;
return myCp;
}
}
Source: https://www.codeproject.com/kb/cs/disableclose.aspx
Related
I have a simple .Net 5.0 WinForm form which is automatically hidden after the application started:
private void form_Shown (object sender, EventArgs e)
{
Hide ();
}
It only creates a notify icon. This notify icon has a context menu strip that is shown by a left mouse click:
private void notifyIcon_Click (object sender, EventArgs e)
{
contextMenuStrip.Show (MousePosition);
}
This works fine, but as long as the context menu strip is visible, a dummy taskbar icon appears:
This doesn't happen if the form is not hidden or the context menu strip is shown by a right mouse click (via ContextMenuStrip property).
How can I prevent this icon?
I finally found a solution myself:
[DllImport ("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern bool SetForegroundWindow (HandleRef hWnd);
private void notifyIcon_Click (object sender, EventArgs e)
{
SetForegroundWindow (new HandleRef (notifyIcon.ContextMenuStrip, notifyIcon.ContextMenuStrip.Handle));
notifyIcon.ContextMenuStrip.Show (MousePosition);
}
Try Me.Hide()
lets see the outcome
Try assign your context menu to the notifyicons .ContextMenu property like and use the notifyicons .Visible property to show it instead of using the .Show method.
I want to have it such that left clicking on the NotifyIcon also causes the context menu (set with the ContextMenuStrip property) to open as well. How would I achieve this? Do I have to handle Click and figure out the positioning myself?
Edit: showing the menu with trayIcon.ContextMenuStrip.Show() results is a few undesirable behaviors:
The menu is not shown at the same location as if right click the NotifyIcon (it appears that you can't set the x and y coords to where the taskbar is, at least on Windows 7 which is what I'm running). It will appear above the task bar (not that big of a deal, but consistency would be nice).
While the menu is shown, there is an extra icon added to the task bar.
Clicking somewhere other than the menu does not close it (whereas if you right click to bring up the context menu clicking else where automatically closes the context menu).
Is it at all possible to just invoke the menu however the built in right click handler is doing it?
You would normally handle the MouseClick event to detect the click and call the ContextMenuStrip.Show() method:
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) {
contextMenuStrip1.Show(Control.MousePosition);
}
But that doesn't actually work properly, the CMS won't close when you click outside of it. Underlying issue is a Windows quirk (aka "bug") that is described in this KB article.
Invoking this workaround in your own code is pretty painful, the pinvoke is unpleasant. The NotifyIcon class has this workaround in its ShowContextMenu() method, they just made it difficult to get to since it is a private method. Reflection can bypass that restriction. I discovered this hack 5 years ago and nobody reported a problem with it yet. Set the NFI's ContextMenuStrip property and implement the MouseUp event like this:
using System.Reflection;
...
private void notifyIcon1_MouseUp(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
MethodInfo mi = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(notifyIcon1, null);
}
}
If you handle MouseUp rather than Click, you will be able to tell which button was clicked, as well as the location of the click. You can use this location as the location to show the ContextMenu
notifyIcon.MouseUp += new MouseEventHandler(delegate(object sender, MouseEventArgs e) { contextMenu.Show(e.Location); });
You can wire in a onClick event for notify icon then call show in the on click
private void wire()
{
notifyIcon1.Click += new EventHandler(notifyIcon1_Click);
}
void notifyIcon1_Click(object sender, EventArgs e)
{
contextMenuStrip1.Show(Cursor.Position);
}
use the following code to show context menu on both right and left click on notifyicon, if you find any issue then text me at arshad_mcs786#hotmail.com (arshad from Islamabd)
//System.Runtime.InteropServices use thi as reference
[DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern bool SetForegroundWindow(HandleRef hWnd);
private void notifyIcon1_Click(object sender, EventArgs e)
{
SetForegroundWindow(new HandleRef(this, this.Handle));
int x = Control.MousePosition.X;
int y = Control.MousePosition.Y;
x = x - 10;
y = y - 40;
this.contextMenuStrip1.Show(x,y );
//this.PointToClient(Cursor.Position)
}
My program makes some changes in the registry while it's running, and if they are not properly rolled back, they might cause the user some problems. FOr example, they might not be able to use their Internet connection.
So I need to make sure that when they close the application, I return everything back to normal. To do this, I need to know when they have pressed the Close button of the form. How can I do that? Is there an event that I can handle?
There is an event you can subscribe to called FormClosing this fire before FormClose and allows you to validate/change the settings you need before the form closes
public Form1()
{
InitializeComponent();
FormClosing += Form1_FormClosing;
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Reset values
}
I think that what you need is not access to the close button, but rather access to the event which is fired when the form is closed.
Taken from this previous SO post, what you might need is something like so:
void FormClosed(object sender, FormClosedEventArgs e)
{
// do something useful
}
There are more possibilites here.
1) Use the FormClosing event of the form:
private void form_FormClosing(object sender, FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing) { // User clicked 'X' button
if (someThing) e.Cancel = true; // Disable Form closing
}
}
2) You can also hide the 'X' button by set ControlBoxto false. But this will also hide the minimize and maximize buttons.
3) This disables only the 'X' button. Place it in your form.
private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams {
get {
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CP_NOCLOSE_BUTTON;
return cp;
}
}
I'm used to reference the current control in access vba, how to do so in C# winform ?
You can also use the form's ActiveControl property.
I took codekaizen's code and dropped it into a form along with a timer and several controls (a DataGridView, Panel, and a Button and CheckBox in the Panel). Added this code in the timer's Tick event:
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = ActiveControl.Name;
label2.Text = GetFocusedControl().Name;
}
and they reported the same active control as I clicked from one control to another.
I'm not sure if there is a better method, but P\Invoke solves this for me:
private static Control GetFocusedControl()
{
Control focused = null;
var handle = GetFocusedControlHandle();
if (handle != IntPtr.Zero)
{
focused = Control.FromHandle(handle);
}
return focused;
}
// ...
[DllImport("user32.dll")]
private static extern IntPtr GetFocusedControlHandle();
I want to have it such that left clicking on the NotifyIcon also causes the context menu (set with the ContextMenuStrip property) to open as well. How would I achieve this? Do I have to handle Click and figure out the positioning myself?
Edit: showing the menu with trayIcon.ContextMenuStrip.Show() results is a few undesirable behaviors:
The menu is not shown at the same location as if right click the NotifyIcon (it appears that you can't set the x and y coords to where the taskbar is, at least on Windows 7 which is what I'm running). It will appear above the task bar (not that big of a deal, but consistency would be nice).
While the menu is shown, there is an extra icon added to the task bar.
Clicking somewhere other than the menu does not close it (whereas if you right click to bring up the context menu clicking else where automatically closes the context menu).
Is it at all possible to just invoke the menu however the built in right click handler is doing it?
You would normally handle the MouseClick event to detect the click and call the ContextMenuStrip.Show() method:
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) {
contextMenuStrip1.Show(Control.MousePosition);
}
But that doesn't actually work properly, the CMS won't close when you click outside of it. Underlying issue is a Windows quirk (aka "bug") that is described in this KB article.
Invoking this workaround in your own code is pretty painful, the pinvoke is unpleasant. The NotifyIcon class has this workaround in its ShowContextMenu() method, they just made it difficult to get to since it is a private method. Reflection can bypass that restriction. I discovered this hack 5 years ago and nobody reported a problem with it yet. Set the NFI's ContextMenuStrip property and implement the MouseUp event like this:
using System.Reflection;
...
private void notifyIcon1_MouseUp(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
MethodInfo mi = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(notifyIcon1, null);
}
}
If you handle MouseUp rather than Click, you will be able to tell which button was clicked, as well as the location of the click. You can use this location as the location to show the ContextMenu
notifyIcon.MouseUp += new MouseEventHandler(delegate(object sender, MouseEventArgs e) { contextMenu.Show(e.Location); });
You can wire in a onClick event for notify icon then call show in the on click
private void wire()
{
notifyIcon1.Click += new EventHandler(notifyIcon1_Click);
}
void notifyIcon1_Click(object sender, EventArgs e)
{
contextMenuStrip1.Show(Cursor.Position);
}
use the following code to show context menu on both right and left click on notifyicon, if you find any issue then text me at arshad_mcs786#hotmail.com (arshad from Islamabd)
//System.Runtime.InteropServices use thi as reference
[DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern bool SetForegroundWindow(HandleRef hWnd);
private void notifyIcon1_Click(object sender, EventArgs e)
{
SetForegroundWindow(new HandleRef(this, this.Handle));
int x = Control.MousePosition.X;
int y = Control.MousePosition.Y;
x = x - 10;
y = y - 40;
this.contextMenuStrip1.Show(x,y );
//this.PointToClient(Cursor.Position)
}