Topmost form, clicking through possible?
You can use SetWindowLong to set the WS_EX_TRANSPARENT window style:
If the layered window has the WS_EX_TRANSPARENT extended window style, the shape of the layered window will be ignored and the mouse events will be passed to the other windows underneath the layered window.
CodeProject has this article detailing the technique. Though it's in VB.NET it should be easy to convert to C#.
I have used the following code in the past:
public enum GWL
{
ExStyle = -20
}
public enum WS_EX
{
Transparent = 0x20,
Layered = 0x80000
}
public enum LWA
{
ColorKey = 0x1,
Alpha = 0x2
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern int GetWindowLong(IntPtr hWnd, GWL nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern int SetWindowLong(IntPtr hWnd, GWL nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
public static extern bool SetLayeredWindowAttributes(IntPtr hWnd, int crKey, byte alpha, LWA dwFlags);
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
int wl = GetWindowLong(this.Handle, GWL.ExStyle);
wl = wl | 0x80000 | 0x20;
SetWindowLong(this.Handle, GWL.ExStyle, wl);
SetLayeredWindowAttributes(this.Handle, 0, 128, LWA.Alpha);
}
but it also was copied from somewhere else. The important lines here are in the OnShown
method. Though I have to admit that the line
wl = wl | 0x80000 | 0x20;
is a little cryptic, setting the WS_EX_LAYERED and WS_EX_TRANSPARENT extended styles.
You can probably also set it like
wl = wl | WS_EX.Layered | WS_EX.Transparent;
Is it possible to keep a Form on top of another, but not TopMost?
Owned forms are always displayed on top of their owner form. To make a form owned by an owner, you can assign a reference of the owner form to Onwer
property of the owned form, for example:
var f = new Form();
f.Owner = this;
f.Show();
Set a Window of another Process as Owner
To do so, you should first find the handle of window of the other process, then using SetWindowLong
API function, you can set it as owner of your form, for example:
//using System.Runtime.InteropServices;
//using System.Diagnostics;
[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
private void button1_Click(object sender, EventArgs e)
{
var notepad = Process.GetProcessesByName("notepad").FirstOrDefault();
if(notepad!=null)
{
var owner = notepad.MainWindowHandle;
var owned = this.Handle;
var i = SetWindowLong(owned, -8 /*GWL_HWNDPARENT*/, owner);
}
}
In above example, your form will be always on top of the notepad window.
this.TopMost = true not working?
TopMost is a property that is used to make sure one window is always shown above all others within an application. Microsofts example was a find and replace tool.
The difference you are finding is that Form1 was created as a modal dialog through the use of ShowDialog. Show dialog makes sure that your form must be closed before all other windows in the application can be used again. For example; using a form to gain user data to enter into a parent forms database.
Show is used when you don't mind if your user has finished with their dialog or not, such as allowing your user the chance to use some utility (e.g timer, stopwatch) that will assist within the main function of a program.
The only visual difference I can think of when using different .Net frameworks, is different windows dialogs such as the OpenFileDialog, that have been updated throughout the framework
Windows Forms: Pass clicks through a partially transparent always-on-top window
You can make a window, click-through by adding WS_EX_LAYERED
and WS_EX_TRANSPARENT
styles to its extended styles. Also to make it always on top set its TopMost
to true
and to make it semi-transparent use suitable Opacity
value:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Opacity = 0.5;
this.TopMost = true;
}
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
const int GWL_EXSTYLE = -20;
const int WS_EX_LAYERED = 0x80000;
const int WS_EX_TRANSPARENT = 0x20;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var style = GetWindowLong(this.Handle, GWL_EXSTYLE);
SetWindowLong(this.Handle,GWL_EXSTYLE , style | WS_EX_LAYERED | WS_EX_TRANSPARENT);
}
}
Sample Result
Opening a WinForms Form with TopMost = true but not having it steal focus?
Paste this code in your form:
protected override bool ShowWithoutActivation
{
get { return true; }
}
How to keep a Form always on top without stealing focus from the active Window?
- Make a standard Form, set its
FormBorderStyle = none
. Make it TopMost (this setting is another topic per se, I'm no going to discuss it here). - Override CreateParams to set the
WS_EX_NOACTIVATE
andWS_EX_TOOLWINDOW
extended styles. This prevents the Form from being activated when mouse events are generated inside its surface (see the docs about these styles). - Add some non-selectable Button Controls to it (the
ButtonNoSel
Control shown below) and set theirTag
property to the Unicode char corresponding to the Emoji image these buttons show. - Add the same Click handler to all the Buttons.
These Buttons, when clicked, simply use SendKeys::Send() (a.k.a. SendInput()
) to send the selected Unicode char to the foreground Window, casting to string the Tag
property value.
This is how it works (setting the Emoji to a Web Page shown by FireFox):
using namespace System;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
using namespace System::Drawing;
public ref class frmKeyBoard : public System::Windows::Forms::Form
{
public:
frmKeyBoard(void) { InitializeComponent(); }
// [...] Initialization...
protected:
property System::Windows::Forms::CreateParams^ CreateParams {
virtual System::Windows::Forms::CreateParams^ get() override {
auto cp = Form::CreateParams;
cp->ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);
return cp;
}
}
// Event handler for all the Buttons
private:
System::Void buttonNoSelAll_Click(System::Object^ sender, System::EventArgs^ e) {
Control^ ctl = safe_cast<Control^>(sender);
SendKeys::Send(ctl->Tag->ToString());
}
};
Add this simple Custom Control to the Project.
This Control simply uses Control.SetStyle, setting ControlStyles::Selectable = false
to prevent the child Control to become the ActiveControl when interacted with, since it doesn't receive the focus.
using namespace System;
using namespace System::Windows::Forms;
using namespace System::ComponentModel;
namespace CustomControls {
[ToolboxItem(true)]
public ref class ButtonNoSel : public System::Windows::Forms::Button
{
public:
ButtonNoSel(void) {
this->InitializeComponent();
this->SetStyle(ControlStyles::Selectable, false);
}
private:
void InitializeComponent(void) {
this->UseVisualStyleBackColor = true;
}
protected:
~ButtonNoSel() { }
};
}
Note that this Form must run on its own thread.
If you need to show this Form from another one, use Task.Run() to show it as a Dialog Window, calling ShowDialog()
. This will start the Message Loop.
For example, from a Button.Click
handler of another Form (here, named MainForm
).
private:
void ShowKeyboard() {
frmKeyBoard^ fk = gcnew frmKeyBoard();
fk->ShowDialog();
delete fk;
}
private:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
Task::Run(gcnew Action(this, &MainForm::ShowKeyboard));
}
How to make a window always stay on top in .Net?
Form.TopMost
will work unless the other program is creating topmost windows.
There is no way to create a window that is not covered by new topmost windows of another process. Raymond Chen explained why.
Related Topics
Custom Sort Logic in Orderby Using Linq
Update App.Config System.Net Setting at Runtime
Serialization Breaks in .Net 4.5
How to Access Gmail API Using Service Account
Formatting Literal Parameters of a C# Code Snippet
How Does Deferred Linq Query Execution Actually Work
Foo.Cmd Won't Output Lines in Process (On Website)
Does "Foreach" Cause Repeated Linq Execution
Resharper Formatting: Align Equal Operands
Thread with Multiple Parameters
How to Parse String with Hours Greater Than 24 to Timespan
Efficient Way to Round Double Precision Numbers to a Lower Precision Given in Number of Bits
C#: How to Add Subitems in Listview
Using String as a Lock to Do Thread Synchronization
How to Implement One "Catch'Em All" Exception Handler with Resume