I'm looking to create a form in C# that cannot accept focus, i.e. when I click a button on the form, focus is not stolen from the application that currently has the focus.
See the Windows on-screen keyboard for an example of this. Note that when you click a button, the focus is not taken from the application you're currently using.
How can I implement this behaviour?
Update:
Turns out it's as simple as overriding the CreateParams property and adding WS_EX_NOACTIVATE to the extended window style. Thanks for pointing me in the right direction!
Unfortunately this has the undesirable side-effect that it messes with form movement, i.e. you can still drag and drop the form around the screen but the window's border is not displayed while dragging so it's difficult to precisely position it.
If anyone knows how to solve this it would be appreciated.
To disable activation by mouse:
class NonFocusableForm : Form
{
protected override void DefWndProc(ref Message m)
{
const int WM_MOUSEACTIVATE = 0x21;
const int MA_NOACTIVATE = 0x0003;
switch(m.Msg)
{
case WM_MOUSEACTIVATE:
m.Result = (IntPtr)MA_NOACTIVATE;
return;
}
base.DefWndProc(ref m);
}
}
To show form without activation (the only one way that worked for me in case of borderless form):
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr handle, int flags);
NativeMethods.ShowWindow(form.Handle, 8);
Standard way to do this (seems like it doesn't work for all form styles):
protected override bool ShowWithoutActivation
{
get { return true; }
}
If there are other ways of activating the form, they can be suppressed in similar manner.
This is the "NoFocusForm" I use:
public class NoFocusForm : Form
{
/// From MSDN <see cref="https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles"/>
/// A top-level window created with this style does not become the
/// foreground window when the user clicks it. The system does not
/// bring this window to the foreground when the user minimizes or
/// closes the foreground window. The window should not be activated
/// through programmatic access or via keyboard navigation by accessible
/// technology, such as Narrator. To activate the window, use the
/// SetActiveWindow or SetForegroundWindow function. The window does not
/// appear on the taskbar by default. To force the window to appear on
/// the taskbar, use the WS_EX_APPWINDOW style.
private const int WS_EX_NOACTIVATE = 0x08000000;
public NoFocusForm()
{
// my other initiate stuff
}
/// <summary>
/// Prevent form from getting focus
/// </summary>
protected override CreateParams CreateParams
{
get
{
var createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_NOACTIVATE;
return createParams;
}
}
}
Related
I have a Form that contains a Panel where I placed a UserControl.
I want that when the Ctrl+F Keys combination is pressed, a TextBox Control, child of my UserControl, gets the Focus.
The structure is like this:
So far, I've tried to handle the KeyPreview and KeyDown events. I can show a MessegeBox:
but I cannot focus the TextBox inside my UserControl.
How can I solve this problem?
You can probably implement IMessageFilter and handle the Keys combinations you want.
You then have to use Application.AddMessageFilter() to add the message filter and Application.RemoveMessageFilter() to remove it when not needed anymore.
Here, the UserControl's DesignMode property is checked, so the filter is added at run.time only.
Possibly, add a public Property that can add / remove / change combinations of Keys, in case there's a conflict with other controls.
The GetAncestor() function is used to determine whether the Form where the Keys combination is triggered is the Parent Form of this instance of the UserControl.
PreFilterMessage() is called when messages are generated in any Form of the application.
If you instead want to perform an action in any case, even when the combination is generated in another open Form (and, maybe, pop the Parent Form in front), just remove that check.
Filter Control + F.
If you need more filters, as mentioned, use a collection to handle these combinations.
When WM_KEYDOWN is received, WParam contains the virtual Key Code. The Virtual Key value is equivalent to the Keys enumerator.
THe ModifierKeys property contains the Key Modifiers currently active (the Control key alone is tested here, of course you can add other shortcuts that use, e.g. CTRL+SHIFT).
using System.ComponentModel;
using System.Runtime.InteropServices;
public partial class SomeUserControl : UserControl, IMessageFilter
{
public SomeUserControl() => InitializeComponent();
public bool PreFilterMessage(ref Message m) {
if (m.Msg == WM_KEYDOWN) {
if (GetAncestor(m.HWnd, GA_PARENT).Equals(ParentForm.Handle)) {
if (m.WParam.ToInt32() == (int)Keys.F && ModifierKeys == Keys.Control) {
someChildTextBox.Focus();
}
}
}
return false;
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
if (!DesignMode) Application.AddMessageFilter(this);
}
protected override void OnHandleDestroyed(EventArgs e) {
if (!DesignMode) Application.RemoveMessageFilter(this);
base.OnHandleDestroyed(e);
}
private const int WM_KEYDOWN = 0x0100;
private const int GA_PARENT = 0x0002;
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetAncestor(IntPtr hWnd, uint flags);
}
I want change the small check-box color beside to item color in checklist in c#
public ColorControl()
{
KnownColor[] colors = Enum.GetValues(typeof(KnownColor)) as KnownColor[];
foreach (var item in colors)
{
this.Items.Add(item.ToString());
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
Color ItemColor = Color.FromName(this.Items[e.Index].ToString());
e.Graphics.DrawString(this.Items[e.Index].ToString(),this.Font,new SolidBrush(ItemColor) ,e.Bounds);
base.OnDrawItem(e);}
Not sure if this is worthy of an answer but here is a shot.
As is mentioned in the answer by Cody Grey The checkbox is not really simple to override. Another alternative besides making your own class inheriting from CheckListBox is to make your own control inheriting from Control. You can use buttons with changing background colors for the checkboxes. And add whatever other features you want.
Something like
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace CustomButton
{
public partial class NeatButton : Control
{
//Some globals
private bool _Pressed = false;
private bool _Activated = false;
//you will want to put your code for clicking checkboxes in the Mouse overrides. The OnPaint override is where you decide how the boxes look.
protected override void OnMouseDown(MouseEventArgs e){...}
protected override void OnMouseUp(MouseEventArgs e){...}
protected override void OnPaint(PaintEventArgs pe){...}
//You will want some propeties
public new string Text
{
get { return base.Text; }
set
{
if (value == base.Text)
return;
base.Text = value;
Invalidate(); //Keeps text showing changes in real time
}
}
/// <summary>
/// Works with Pressed to determine if the button should do something when clicked. **Use a property like this for the checkboxes**
/// </summary>
private bool Activated
{
get { return _Activated; }
set
{
if (value == _Activated)
return;
_Activated = value;
Invalidate();
}
}
/// <summary>
/// Works with Activated to determine if the button should do something when clicked
/// </summary>
private bool Pressed
{
get { return _Pressed; }
set
{
if (value == _Pressed)
return;
_Pressed = value;
Invalidate();
}
}
While this is not a complete example it should show a very basic set up for a custom control.
Once the custom control is working then want to build it and grab the exe from where ever you built it. Then in the form you want to use it in you drop the exe in to the project folder. Then in the solution explorer right click on References and then Add reference. Then browes to your exe and check it off and click 'OK'. Save your project and open up the form designer. Right click on the ToolBox and click Choose Items. Find your exe and check it off and hit ok. The Checkbox you made should now appear in the tool box and can be dragged and dropped onto a form and used like any other control.
Good luck.
The checkbox is drawn by the operating system. It is intentionally designed so that it looks like every other checkbox on the screen. This massively helps with usability. Users will not know what they can click on a red box and use it like a checkbox.
If you insist on making your application difficult to use, you will have to owner-draw the control. It will not be easy, CheckedListBox is not designed to support owner-drawing. The DrawItem event is documented as being "not relevant to this class." The control is already owner-drawn by the framework.
At the very least, you will need to create a new class that inherits from CheckedListBox so that you can override the OnDrawItem method.
public class ColorCheckBoxListBox : CheckedListBox
{
protected override void OnDrawItem(DrawItemEventArgs e)
{
// ...
}
}
I have an Outlook 2013 VSTO addin. I want to center my saveFileDialog that I create. To do this you need to pass it a Window object of the parent. I'm not sure if IWin32Window and Window are the same, but here's what I have.
public IWin32Window getWindowHandle()
{
dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow();
IntPtr outlookHwnd = new OfficeWin32Window(activeWindow).Handle;
IWin32Window win = Control.FromHandle(outlookHwnd);
return win;
}
The SaveFileDialog.ShowDialog(Window) method takes a window. Can I pass it the IWin32Window? Is there a way to get the Window object from the handler other than Control.FromHandle?
Any criticisms would be welcome.
Thanks
EDIT:
Oh and the helper class for that function:
public class OfficeWin32Window : IWin32Window
{
[DllImport("user32")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
IntPtr _windowHandle = IntPtr.Zero;
public IntPtr Handle
{
get { return _windowHandle; }
}
public OfficeWin32Window(object windowObject)
{
string caption = windowObject.GetType().InvokeMember("Caption", System.Reflection.BindingFlags.GetProperty, null, windowObject, null).ToString();
// try to get the HWND ptr from the windowObject / could be an Inspector window or an explorer window
_windowHandle = FindWindow("rctrl_renwnd32\0", caption);
}
}
I was given this code, so I do have a side question about it: What does FindWindow("rctrl_renwnd32\0", caption) do? I don't get it at all. Especially the "rctrl_renwnd32\0" part.
EDIT:
New function with IOleWindow class:
public IOleWindow getWindowHandle()
{
dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow();
IOleWindow win = activeWindow as IOleWindow;
window = win.GetWindow();
//IntPtr outlookHwnd = new OfficeWin32Window(activeWindow).Handle;
//IWin32Window wind = Control.FromHandle(outlookHwnd);
return window;
}
EDIT2:
My updated logic, I removed the function and added this in the place I need tthe handle:
Inspector currentObject = Globals.ThisAddIn.Application.ActiveInspector();
var winh = currentObject as IOleWindow;
IntPtr win = winh.GetWindow();
EDIT3:
Restructured:
Inspector currentObject = Globals.ThisAddIn.Application.ActiveInspector();
var winh = currentObject as IOleWindow;
IntPtr win;
winh.GetWindow(out win);
The FindWindow method retrieves a handle to the top-level window whose class name and window name match the specified strings. The first parameter specifies the window class name. The second parameter is the window name (the window's title). If this parameter is NULL, all window names match.
Instead of using the FindWindow function you need to cast the Explorer or Inspector window to the IOleWindow interface and use the GetWindow method to get the window handle.
/// <summary>
/// Implemented and used by containers and objects to obtain window handles
/// and manage context-sensitive help.
/// </summary>
/// <remarks>
/// The IOleWindow interface provides methods that allow an application to obtain
/// the handle to the various windows that participate in in-place activation,
/// and also to enter and exit context-sensitive help mode.
/// </remarks>
[ComImport]
[Guid("00000114-0000-0000-C000-000000000046")]
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleWindow
{
/// <summary>
/// Returns the window handle to one of the windows participating in in-place activation
/// (frame, document, parent, or in-place object window).
/// </summary>
/// <param name="phwnd">Pointer to where to return the window handle.</param>
void GetWindow (out IntPtr phwnd) ;
/// <summary>
/// Determines whether context-sensitive help mode should be entered during an
/// in-place activation session.
/// </summary>
/// <param name="fEnterMode"><c>true</c> if help mode should be entered;
/// <c>false</c> if it should be exited.</param>
void ContextSensitiveHelp ([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode) ;
}
An instance of the IWin32Window interface is used to specify the parent window handle for the Show or ShowDialog methods.
To reproduce this bug you need to create custom ToolStripItem, using ToolStripControlHost.
In my case, I made ToolStripDateTimePicker control (as seen on many good tutorials). The control however behaves slightly different than a regular DateTimePicker.
Regular one produces default Windows bell sound when ESC is pressed while it's active. The ToolStrip hosted control reacts for ESC pressed in a more sensible manner. The control becomes inactive, no beep.
Here's the bug part: when focusing another control with a click - regular DateTimePicker triggers Leave event. As expected. ToolStrip hosted control DOES NOT trigger any event!
Yes, I've tried KeyDown event - it's not sent when ESC key is pressed, but sent when any other key is pressed.
I believe it's a bug in .NET itself.
The consequence of this is broken focus behavior of the form containing the ToolStrip control. The form cannot be focused again after entering ToolStrip hosted control.
But it's a workaround for this: you can focus an other form (or even maybe another control), and then the target form - it works for me.
However I would like to have it done automatically - the moment user exits the hosted control. The problem is I don't have an event for this. Any ideas?
What's weird, Leave event is eventually triggered when the hosted control is disposed - it's clearly a bug, because the event is totally useless there.
Here: sample application illustrating the problem
I've replaced it with sample workaround, to see the problem comment out OnGotFocus() and OnLostFocus() overrides.
It worked nice (and could not reproduce the bug) until I've changed FlowLayoutPanel TabIndex to 0, so the DateTimePicker is not active when the application starts.
Here's what I learned:
The problem was not exactly with ToolStripControlHost class, but with the DateTimePicker control itself, and to be more specific - with it's interaction with FlowLayoutPanels and possibly other similar controls. And I'm not sure if it's a bug or expected behavior, but seems more like a bug.
Here's how it works:
If there is another control which can be obviously activated (like TextBox), leaving the DatePickerControl means activating the other control. But if the other control is empty container, or container with no controls which can be activated - Leave event is not triggered despite the DateTimePicker control is not active anymore.
Why would you want to have a container with no active controls active itself? I use FlowLayoutPanel to produce a read-only, non-editable report. It is not editable, but I want it scrollable, and I don't want DateTimePicker control to steal focus from FlowLayoutPanel - so in this case FlowLayoutPanel is an active control.
Of course it doesn't work this way. There are more workarounds needed for such behavior to be achieved, like receiving mouse events from containing form, but correct Focus/Leave behavior for ToolStripDatePickerControl is a good start.
So without further ado, my perfect ToolsStripDateTimePicker control, with focus glitch fixed:
DesignerToolStripControlHost class:
namespace System.Windows.Forms {
/// <summary>
/// Fixes ToolStripControlHost broken designer behavior
/// </summary>
public class DesignerToolStripControlHost : ToolStripControlHost {
/// <summary>
/// Fixes designer bug by creating a constructor allowing to create ToolStripControlHost
/// without parameter
/// </summary>
public DesignerToolStripControlHost() : base(new UserControl()) { }
/// <summary>
/// Initializes a new instance of the System.Windows.Forms.DesignerToolStripControlHost
/// class that hosts the specified control
/// </summary>
/// <param name="c"></param>
public DesignerToolStripControlHost(Control c) : base(c) { }
/// <summary>
/// Initializes a new instance of the System.Windows.Forms.DesignerToolStripControlHost
/// class that hosts the specified control and that has the specified name
/// </summary>
/// <param name="c"></param>
/// <param name="name"></param>
public DesignerToolStripControlHost(Control c, string name) : base(c, name) { }
}
}
ToolStripDateTimePicker class:
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace System.Windows.Controls {
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public partial class ToolStripDateTimePicker : DesignerToolStripControlHost, IComponent {
public ToolStripDateTimePicker() : base(new DateTimePicker() { Margin = new Padding(0, 0, 0, 0), Width = 150, Value = DateTime.Now.Date }) { }
#region Properties
[Browsable(true)]
[Category("Design")]
[Description("Internal ToolStrip hosted control.")]
public DateTimePicker DateTimePickerControl { get { return Control as DateTimePicker; } }
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[Category("Behavior")]
[Description("Gets or sets the tab order of the control within its container.")]
public int TabIndex { get { return DateTimePickerControl.TabIndex; } set { DateTimePickerControl.TabIndex = value; } }
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[Category("Behavior")]
[Description("Gets or sets a value indicating whether the user can give the focus to this control using the TAB key.")]
public bool TabStop { get { return DateTimePickerControl.TabStop; } set { DateTimePickerControl.TabStop = value; } }
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[Description("This property is ignored.")]
public override string Text { get { return DateTimePickerControl.Value.ToString(); } set { DateTimePickerControl.Value = DateTime.Parse(value); } }
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[Category("Behavior")]
[Description("The current date/time value for this control.")]
public DateTime Value { get { return DateTimePickerControl.Value; } set { DateTimePickerControl.Value = value; } }
#endregion
#region Events
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[Category("Focus")]
[Description("Occurs when the input focus enters the control.")]
public new EventHandler Enter;
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[Category("Focus")]
[Description("Occurs when the input focus leaves the control.")]
public new EventHandler Leave;
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[Category("Behavior")]
[Description("Occurs when the value of the control changes.")]
public event EventHandler ValueChanged;
#endregion
#region Event Handlers
protected void OnEnter(object sender, EventArgs e) { EventHandler handler = Enter; if (handler != null) handler(this, e); }
protected void OnLeave(object sender, EventArgs e) { EventHandler handler = Leave; if (handler != null) handler(this, e); }
protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
if (Enter != null) {
if (DateTime.Now.Ticks - _FocusGlitchFix_LastEvent > _FocusGlitchFixTickWindow) Enter.Invoke(this, e);
_FocusGlitchFix_LastEvent = DateTime.Now.Ticks;
}
}
protected override void OnLostFocus(EventArgs e) {
base.OnLostFocus(e);
if (Leave != null) {
if (DateTime.Now.Ticks - _FocusGlitchFix_LastEvent > _FocusGlitchFixTickWindow) Leave.Invoke(this, e);
_FocusGlitchFix_LastEvent = DateTime.Now.Ticks;
}
}
protected void OnValueChanged(object sender, EventArgs e) { EventHandler handler = ValueChanged; if (handler != null) handler(this, e); }
protected override void OnSubscribeControlEvents(Control control) {
base.OnSubscribeControlEvents(control);
DateTimePickerControl.ValueChanged += new EventHandler(OnValueChanged);
}
protected override void OnUnsubscribeControlEvents(Control control) {
base.OnUnsubscribeControlEvents(control);
DateTimePickerControl.ValueChanged -= new EventHandler(OnValueChanged);
}
#endregion
#region Focus Glitch Workaround data
private long _FocusGlitchFix_LastEvent = 0;
private readonly long _FocusGlitchFixTickWindow = 100000; // 10ms
#endregion
}
}
Workarounds explained:
Original DTP OnGotFocus() and OnLostFocus() event handlers are overridden to trigger my new control Enter and Leave events. Note that they are triggered almost correctly.
When the control is the only one which can be activated, when the control is first left it's activated and deactivated instantly - which means doubled (redundant) Enter and Leave events. We don't want those, so I check the time between events, if it's smaller than 10ms I just ignore later event.
DesignerToolStripControlHost is used to fix broken designer behavior. If you used ToolStripControlHost directly, you would get an exception trying to show the control's designer view, because designer tries to instantiate this class with no argument, and this class does not have a constructor with no argument. So my new class does.
When designer view of a form containing ToolStripDateTimePicker break which you can tell by seeing DTP disappeared, just close designer view and open it again. It will work fine until you compile or debug your application again.
Glitch fix was tested with 1ms time window and worked fine. So I chose 10ms to ensure it works on slower or more loaded machines, but it's still short enough to capture any event from user interaction.
I have a form that represents a USB device Terminal that has been giving me some errors. After half a day of debugging strange errors with no known source I somehow found out that the Terminal does not function when it is instantiated but not shown. When I change the code and add usbTerminal.Show();, then it works properly.
USBTerminal usbTouchTerminal;
public MainForm()
{
InitializeComponent();
USBSettings usbTouchSettings = new USBSettings();
usbTouchTerminal = new USBTerminal(usbTouchSettings); //Create Terminal with settings
usbTouchTerminal.StartUSB();
usbTouchTerminal.Show(); //works ONLY when show is here
}
How is this possible and why? I've done a massive search and none of my code depends on the .Visible property on either my Terminal or main form?
I'm completely baffled on why some form would not work if it isn't shown. MSDN or google wasn't really a help either. I was certain it would function properly when instantiated but not shown.
PS. I added
usbTerminal.Show();
usbTerminal.Hide();
and the Terminal functioned correctly.
Thank you for any help!
EDIT:
I should also note that this usbTerminal uses the WndProc override. I'm not an expert on that, but I feel that it may have something to do with it.
I should note that this is LibUSBdotnet
public class USBSettings
{
/// <summary>
/// This is the Vender ID Number. (0x0B6A)
/// </summary>
public ushort VID { get; set; }
/// <summary>
/// This is the Product ID Number. (0x5346)
/// </summary>
public ushort PID { get; set; }
/// <summary>
/// This is the optional Serial Name. ("")
/// </summary>
public string SerialName { get; set; }
/// <summary>
/// This is the Reader USB Endpoint. (ReadEndpointID.Ep02)
/// </summary>
public ReadEndpointID ReaderEndpoint { get; set; }
/// <summary>
/// This is the Writer USB Endpoint. (WriteEndpointID.Ep01)
/// </summary>
public WriteEndpointID WriterEndpoint { get; set; }
/// <summary>
/// This is the Registry Key for USB settings. ("SOFTWARE\\DEFAULT\\USBPROPERTIES")
/// </summary>
public string SubKey { get; set; }
/// <summary>
/// This is the default read buffer size for the USB Device.
/// </summary>
public int ReadBufferSize { get; set; }
/// <summary>
/// This constructor houses default values for all properties.
/// </summary>
public USBSettings()
{
VID = 0x0B6A;
PID = 0x5346;
SerialName = "";
ReaderEndpoint = ReadEndpointID.Ep02;
WriterEndpoint = WriteEndpointID.Ep01;
SubKey = "SOFTWARE\\DEFAULT\\USBPROPERTIES";
ReadBufferSize = 100;
}
}
The question is poorly documented but this is fairly normal for code that works with devices. They tend to need to know about Plug & Play events and that requires a top-level window to be created that receives the WM_DEVICECHANGE notification message. Creating a .NET Form object isn't enough, you also have to create the native window for it. Which, in typical .NET lazy fashion, happens at the last possible moment, when you force the window to be visible. Either by calling the Show() method or setting the Visible property to true. The window doesn't actually have to be visible to get the Plug & Play notifications.
You can get the window created without also making it visible. That requires modifying the USBTerminal class. Paste this code:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
And call the Show() method as normal. Beware that the Load event won't fire until the window actually becomes visible so if necessary move any code in the event handler to this method. If this is not the primary window for the app, in other words not the one that's passed to Application.Run() in your Main() method, then you can make do with simply calling this.CreateHandle() as the last statement in the form constructor. In which case calling Show() is no longer necessary.
I suspect this is because the underlying window is not created before you call Show(). Since the window isn't created, your custom WndProc isn't called.
To verify, you can create the window without showing it - by looking at the Handle property. As the documentation says - if the handle has not been created by the time you call, it will be created. Try it, I bet it'll work just as if you called Show and then Hide.
It is very hard to tell from the information you have but I think you are using a form where a class should be used. You should rethink your program structure and re-write this as a class to hold and transmit the data as you need. As some of the other have pointed out the listbox and/or other function are not running until the form is shown and the methods is executed.
Because some required functions will be called when Form onShow event called.