I\'m having some issues getting a notification box to behave correctly in c#. Basically I\'m showing a boarderless form in the lower right hand side of the screen, which dis
I'm not looking for points here as the original poster already posted a solution that worked for them but I wanted to share my experience with this problem. Using the solution above (which is at the bottom of the question instead of in answer form) gives me a Win32Exception: Error creating window handle error.
when using the WndProc
code as it is posted there. The ShowWithoutActivation
and CreateParams
part works great to prevent activation of a form and still keep it topmost.
I came up with an alternate solution to preventing a form from being clicked using SetWindowLong
which makes the form transparent and therefore it can be clicked through and SetLayeredWindowAttributes
which sets the transparency back to normal so you can see the form again but still retain the ability to click through the form.
NOTE: You -CANNOT- interact with the form at all in this state and even trying to click the 'X' button will just click whatever is behind the form at that position so you will need to use code to close the form:
public partial class Form1 : Form
{
private enum GWL : int
{
ExStyle = -20
}
private enum WS_EX : int
{
Transparent = 0x20,
Layered = 0x80000
}
public enum LWA : int
{
ColorKey = 0x1,
Alpha = 0x2
}
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
protected override bool ShowWithoutActivation
{
get { return true; }
}
const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams param = base.CreateParams;
param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
return param;
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Prevent form from showing up in taskbar which also prevents activation by Alt+Tab
this.ShowInTaskbar = false;
// Allow the form to be clicked through so that the message never physically interferes with work being done on the computer
SetWindowLong(this.Handle, (int)GWL.ExStyle, (int)WS_EX.Layered | (int)WS_EX.Transparent);
// Set the opacity of the form
byte nOpacity = 255; // 0 = invisible, 255 = solid, anything inbetween will show the form with transparency
SetLayeredWindowAttributes(this.Handle, 0, nOpacity, (uint)LWA.Alpha);
}
}
I was also able to get the original approach working by making a small change to the WndProc
code above.
NOTE: This also makes the form unclickable but the behavior is different in that you can actually click the min, max and 'X' buttons but nothing happens when you do. The mouse cursor also changes when you are at the edge of the form as if to resize but it doesn't allow resizing:
public partial class Form1 : Form
{
protected override bool ShowWithoutActivation
{
get { return true; }
}
const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams param = base.CreateParams;
param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
return param;
}
}
[DllImport("user32.dll")]
private extern static IntPtr SetActiveWindow(IntPtr handle);
private const int WM_ACTIVATE = 6;
private const int WA_INACTIVE = 0;
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
return;
}
if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
{
if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
{
if (m.LParam != IntPtr.Zero)
{
SetActiveWindow(m.LParam);
}
else
{
// Could not find sender, just in-activate it.
SetActiveWindow(IntPtr.Zero);
}
}
}
else
{
base.WndProc(ref m);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Prevent form from showing up in taskbar which also prevents activation by Alt+Tab
this.ShowInTaskbar = false;
}
}
In WPF try this:
ShowActivated="False"
Possibly WS_EX_NOACTIVATE extended window style is what you are looking for. Window with this style is not activated when clicked. For example, Virtual Keyboard window has this style.
To apply this style to window, override CreateParams function and change baseParams.ExStyle.