Remove the Icon Double-click close feature in WinForms? - c#

I would like to keep the icon on my program, but would like to remove the double-click close
feature. Is there any way of doing this?
I have not found anything about this on google tho.

You can do this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Size iconSize = new Size(32,32);
Rectangle R = new Rectangle(this.Location, iconSize);
if (R.Contains(Cursor.Position) && e.CloseReason == CloseReason.UserClosing)
e.Cancel = true;
}

Here are two options. The side effect is that the window's top right X (close button) is disabled on Windows 8. I believe on windows XP it is removed completely.
Option 1: Override the Form's OnHandleCreated:
[DllImport("user32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
public static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("user32.dll")]
private static extern bool RemoveMenu(IntPtr hMenu, int uPosition, uint uFlags);
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
const uint MF_BYPOSITION = 0x00000400;
IntPtr hMenu = GetSystemMenu(this.Handle, false);
int n = GetMenuItemCount(hMenu);
RemoveMenu(hMenu, n-1, MF_BYPOSITION); // remove last (always close?)
}
Option 2: override the Form's CreateParams. The advantage of this one is that it does the work of also removing the separator.
// this code will hide the close X button, since there is no CloseBox Form property
protected override CreateParams CreateParams {
get {
const int CS_NOCLOSE = 0x0200;
CreateParams param = base.CreateParams;
param.ClassStyle = param.ClassStyle | CS_NOCLOSE;
return param;
}
}

Related

How to create a non active dropdown with keybord focus

I want to create a dropdown control which should be inactive and have keyboard input focus. So I created a control as below.
public class DropDownEdit : UserControl
{
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private const int WS_EX_TOOLWINDOW = 0x00000080;
private const int WS_EX_TOPMOST = 0x00000008;
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int WS_CHILD = 0x40000000;
private const int WS_POPUP = unchecked((int)0x80000000);
private TextBox text = new TextBox();
public DropDownEdit()
{
this.BackColor = Color.FromArgb(44, 68, 107);
this.Controls.Add(text);
this.Margin = Padding.Empty;
this.Padding = new Padding(0);
text.Multiline = true;
text.ScrollBars = ScrollBars.Both;
text.Size = new Size(this.Width, this.Height);
}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.Style &= ~WS_CHILD;
createParams.Style |= WS_POPUP;
createParams.ExStyle |= WS_EX_TOOLWINDOW;
createParams.ExStyle |= WS_EX_TOPMOST;
createParams.ExStyle |= WS_EX_NOACTIVATE;
return createParams;
}
}
public void ShowWindow(Point point)
{
text.Focus();
this.Capture = true;
SetParent(this.Handle, IntPtr.Zero);
this.Location = point;
Show();
}
protected override void OnMouseCaptureChanged(EventArgs e)
{
base.OnMouseCaptureChanged(e);
this.Hide();
}
}
And when I am displaying the above dropdown window as below,
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Point point = this.PointToScreen(button1.Location);
DropDownEdit window = new DropDownEdit();
window.ShowWindow(new Point(point.X, point.Y + 20));
}
}
The Form1 has a flickering while displaying DropDownEdit. I think DropDownEdit get activated and Form1 loses its activation. How can I avoid this flickering in Form1?
NB:- I need input focus on TextBox in the dropdown control.
I found a solution.
While displaying my dropdown window it will receive activation and Windows will deactivate the main window. The fix for this is to send a WM_NCACTIVATE message to the parent to update its visual appearance without changing its activation status.
The below code is updated in DropDownEdit class to solve my issue.
private const int WM_NCACTIVATE = 0x86;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
protected override void WndProc(ref Message m)
{
// The popup needs to be activated for the user to interact with it,
// but we want to keep the owner window's appearance the same.
if ((m.Msg == WM_NCACTIVATE) && !_activating && (m.WParam != IntPtr.Zero))
{
// The popup is being activated, ensure parent keeps activated appearance
_activating = true;
SendMessage(this.Owner.Handle, WM_NCACTIVATE, (IntPtr) 1, IntPtr.Zero);
_activating = false;
// Call base.WndProc here if you want the appearance of the popup to change
}
else
{
base.WndProc(ref m);
}
}

in winforms, how can i make a control not accept mouse events

I have a button and upon mouseenter, a little form pops up, and upon mouseleave of the button, the little form disappears. I am needing this form to not accept any mouse events, in other words, be "invisible" to the mouse.
The problem is, the form pops up under the mouse, which triggers the mouseleave event for the button. I know there are other ways to get around this, but i'm needing the form to hide when the mouse leaves the original button that triggered the form, and I also need the form to appear underneath the mouse.
So how can I make the little pop-up form invisible to mouse-events, so that it doesn't cause the "mouse leave" event to trigger for the button?
The popup is of type "Form". Here is the mouseEnter and mouseLeave code that triggers showing and hiding the form:
private void btnPatientSearch_MouseEnter(object sender, EventArgs e)
{
_currentPatientInfo = new PatientInfo()
{
MdiParent = this.MdiParent
};
_currentPatientInfo.Show();
_currentPatientInfo.Location = new Point(181, 9);
}
}
private void btnPatientSearch_MouseLeave(object sender, EventArgs e)
{
if (_currentPatientInfo == null) return;
_currentPatientInfo.Hide();
_currentPatientInfo = null;
}
Inherit your popup form from the following form class. This code is using some p/invokes and not tested, but it should work.
public class PopupForm : Form
{
private const int WS_BORDER = 0x00800000;
private const int WS_POPUP = unchecked((int)0x80000000);
private const int WS_EX_TOPMOST = 0x00000008;
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 4;
private static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1);
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, int uFlags);
public PopupForm()
{
SetStyle(ControlStyles.Selectable, false);
FormBorderStyle = FormBorderStyle.None;
StartPosition = FormStartPosition.Manual;
ShowInTaskbar = false;
Visible = false;
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= WS_POPUP | WS_BORDER;
cp.ExStyle |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;
return cp;
}
}
protected override bool ShowWithoutActivation
{
get { return true; }
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
OnClick(EventArgs.Empty);
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
}
else
base.WndProc(ref m);
}
public new void Show()
{
Windows.SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
base.Show();
}
}

Disable Close Button In Title Bar of a WPF Window (C#)

I'd like to know how to disable (not remove/hide) the Close button in a WPF window. I know how to hide it which makes the window's title bar look like this:
But I want to disable it meaning it should look like this:
I'm scripting in C# and using WPF (Windows Presentation Foundation).
Try this:
public partial class MainWindow : Window
{
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
const uint MF_BYCOMMAND = 0x00000000;
const uint MF_GRAYED = 0x00000001;
const uint SC_CLOSE = 0xF060;
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Disable close button
IntPtr hwnd = new WindowInteropHelper(this).Handle;
IntPtr hMenu = GetSystemMenu(hwnd, false);
if (hMenu != IntPtr.Zero)
{
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
}
}
Taken from here.
Make sure you set the ResizeMode to NoResize.
You have to override and in OnCLosing event set e.cancel=true
public MyWindow()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(MyWindow_Closing);
}
void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
This post which an answer using Behavior, GetWindowLong and SetWindowLong:
public class HideCloseButtonOnWindow : System.Windows.Interactivity.Behavior<Window>
{
#region bunch of native methods
private const int GWL_STYLE = -16;
private const int WS_SYSMENU = 0x80000;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
#endregion
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += OnLoaded;
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= OnLoaded;
base.OnDetaching();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var hwnd = new System.Windows.Interop.WindowInteropHelper(AssociatedObject).Handle;
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
}
}
How to use it:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:w="clr-namespace:WpfApplication2">
<i:Interaction.Behaviors>
<w:HideCloseButtonOnWindow />
</i:Interaction.Behaviors>
</Window>
You can probably do it with win32 hackery.
I have done it this way: Get CustomChromeWindow(which will eventually look exactly like the one in picture), and just bind Command() property to viewmodel, and then set CanExecuteCommand=false, which will make the button disabled(How does one "disable" a button in WPF using the MVVM pattern?).
There might me this way too: How to disable close button on a window in another process with C++?
Basically, call that code with pInvoke. You can obtain WPF window handle easily.
If you would like a more generic version of Yoav's accepted answer that doesn't require adding Win API calls to your Window class, here's a extension class and method:
namespace WinApi
{
using System.Runtime.InteropServices;
using System.Windows.Interop;
public static class WinApi
{
[DllImport("user32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
public static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
const uint MF_BYCOMMAND = 0x00000000;
const uint MF_GRAYED = 0x00000001;
const uint SC_CLOSE = 0xF060;
public static void DisableCloseButton(this System.Windows.Window window)
{
// Disable close button
IntPtr hwnd = new WindowInteropHelper(window).EnsureHandle();
IntPtr hMenu = GetSystemMenu(hwnd, false);
if (hMenu != IntPtr.Zero)
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
}
}
Then call it from your Window like so:
this.DisableCloseButton();
// or
WinApi.DisableCloseButton(this);
Since the extension uses EnsureHandle() you don't need to hook OnSourceInitialized() in your Window.
Be aware that EnsureHandle() raises OnSourceInitialized(), so don't call this until after you have done anything you want to happen prior to that call.
You can call new WindowInteropHelper(this).Handle() in your Window code if you need to check whether the handle has already been created.

How to remove the close button, but not its icon?

I have a windows application develop using C# .net 4.0 version.
I need to remove close button from one of my popup windows. I can do it by setting Control Box property as false. But in that case it will remove my icon as well. Else I can disable the close button. But is there any way to remove close button only (leaving the icon in place)?
This is a bit of a cleaner solution :-)
Original post
winuser.h
public partial class Form1 : Form
{
private const int CS_NOCLOSE = 0x200;
protected override CreateParams CreateParams
{
get
{
CreateParams mdiCp = base.CreateParams;
mdiCp.ClassStyle = mdiCp.ClassStyle | CS_NOCLOSE;
return mdiCp;
}
}
public Form1()
{
InitializeComponent();
}
}
According to constants in the winuser.h there are no flags to get rid of the closed button completely. (Unless you want to find a way to draw over the top of the button by copying a section to the left of it - yuk.)
This code will disable your close button but will show the icon.
In your form class:
Import:
using System.Runtime.InteropServices;
In the main class:
const int MF_BYPOSITION = 0x400;
[DllImport("User32")]
private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags);
[DllImport("User32")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("User32")]
private static extern int GetMenuItemCount(IntPtr hWnd);
Event:
private void Form1_Load(object sender, EventArgs e)
{
IntPtr hMenu = GetSystemMenu(this.Handle, false);
int menuItemCount = GetMenuItemCount(hMenu);
RemoveMenu(hMenu, menuItemCount - 1, MF_BYPOSITION);
}

Opening a WinForms Form with TopMost = true but not having it steal focus?

I have a form that pops up on a user's screen and has TopMost=true, but it steals the focus. How can I get it to not steal focus when it first appears?
This is what worked for me. It provides TopMost but without focus-stealing.
protected override bool ShowWithoutActivation
{
get { return true; }
}
private const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_TOPMOST;
return createParams;
}
}
Remember to omit setting TopMost in Visual Studio designer, or elsewhere.
This is stolen, err, borrowed, from here (click on Workarounds):
https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost
Paste this code in your form:
protected override bool ShowWithoutActivation
{
get { return true; }
}
You can set:
this.TopMost = True;
on Load event of that form.
It's OK with me!
You can do it like this:
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
int X, // Horizontal position
int Y, // Vertical position
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(System.IntPtr hWnd, int nCmdShow);
public static void ShowInactiveTopmost(System.Windows.Forms.Form frm)
{
try
{
ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
frm.Left, frm.Top, frm.Width, frm.Height,
SWP_NOACTIVATE);
}
catch (System.Exception ex)
{
// error handling
}
}
I tested the below code using a timer on form1 to instantiate and show form2 with form1 as owner.
In form2's Shown event I then set focus to the owner, which is the current active form.
I have a textbox on form1 and was able to continuesly write in the textbox without loosing focus during this process.
My timer code in form1:
private void timer1_Tick(object sender, EventArgs e)
{
Form2 popup = new Form2();
popup.TopMost = true;
popup.Show(this);
timer1.Enabled = false;
}
My code in the Shown event of form2:
private void Form2_Shown(object sender, EventArgs e)
{
this.Owner.Focus();
}
You can do this or simply set TopMost to false and use the override of ShowWithoutActivation as Hans Passant stated.
Edit: (Or use p/invoke as seen in Hans Passant's additional comment I missed while I wrote this)
I came across the same problem. I'm not using C# but C++. I figure this could be useful anyways:
Using windows.h:
BOOL WINAPI SetWindowPos(
__in HWND hWnd,
__in_opt HWND hWndInsertAfter,
__in int X,
__in int Y,
__in int cx,
__in int cy,
__in UINT uFlags
);
Passing the flag SWP_NOACTIVATE to the uFlags argument worked for me.
Instead of writing .setfocus()in _activated event; write it to .shown event of the form.

Categories