I am trying to make a Windows Forms Application be able to repeatedly show and then hide itself.
The idea is to create a small app that overlays an image on the screen every time a modifier key like Num Lock or Caps lock is pressed. I have the detection of the keyboard keys working flawlessly, but I am not having much luck with creating a form that I can show and then hide repeatedly.
The way I see it, (please correct me if I'm wrong) there are two possible ways to make the form behave like I want it to:
- Start the form normally in
Program.cs
and then hold the logic for hiding and showing the form and displaying the image insideForm1.cs
- The form would call
this.Hide()
andthis.Show()
to hide and show itself, but whenever I try to do this, I cannot getthis.Hide()
to hide the form; the form remains visible on top of all of the open windows.
- The form would call
- Hold the logic for hiding and showing the form in
Program.cs
and then just hold the logic to display the image inForm1.cs
- I've been toying around with the code from this guide to show and hide the from from
Program.cs
with a class wrapper for the form, but as it turns out,form.Showdialog()
prevents any further code execution until the form is closed.
- I've been toying around with the code from this guide to show and hide the from from
I've been playing around with the code myself, and neither of the above methods have worked. Am I thinking about this in the wrong way entierly? Can a WFA ever behave in the way I want it to?
The code for this is a bit messy, and I'm not sure what parts are the most relevant here, but I'll do my best to include it here:
Program.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace KeyboardIndicators {
// ApplicationContext wrapper
public abstract class TrayIconApplicationContext : ApplicationContext {
private NotifyIcon lockIcon;
private ContextMenu lockIconContext;
protected TrayIconApplicationContext() {
// Wire up the ApplicationExitHandler to ApplicationExit events
Application.ApplicationExit += this.ApplicationExitHandler;
lockIconContext = new ContextMenu {
};
// Create lockIcon tray icon and make it visible
lockIcon = new NotifyIcon {
ContextMenu = lockIconContext,
Text = Application.ProductName,
Icon = new Icon("icon.ico"),
Visible = true
};
}
protected NotifyIcon LockIcon { get { return lockIcon; } }
protected ContextMenu LockIconContext { get { return lockIconContext; } }
// ApplicationExit event handler
private void ApplicationExitHandler(object sender, EventArgs e) {
this.OnApplicationExit(e);
}
// Performs cleanup to end the application
protected virtual void OnApplicationExit(EventArgs e) {
// TODO(Neil): Add meaningful thread cleanup here soon
if (lockIcon != null) {
lockIcon.Visible = false;
lockIcon.Dispose();
}
if (lockIconContext != null)
LockIconContext.Dispose();
}
}
// TrayIconApplicationContext wrapper for Form1 to control the activation of the form window
class FormApplicationContext : TrayIconApplicationContext {
public FormApplicationContext() {
// Add Exit menu item
MenuItem exit = new MenuItem("E&xit");
this.LockIconContext.MenuItems.Add(exit);
exit.Click += this.ExitContextMenuClickHandler;
//KeyboardIndicators indicators = new KeyboardIndicators();
//indicators.RunListener();
{
using(Form form = new Form1("NumLock", true))
form.ShowDialog();
}
}
private void ExitContextMenuClickHandler(object sender, EventArgs eventArgs) {
this.ExitThread();
}
}
public class KeyboardIndicators {
class LockState {
// Is the numlock key on?
public bool Num;
// Is the capslock key on?
public bool Caps;
// Is the scroll lock key on?
public bool Scroll;
}
public void RunListener() {
try {
// Store the old keyboard lock state
LockState prevState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
while (true) {
// Store the new keyboard lock state
LockState newState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
//TODO(Neil): Handle simultaneous presses better, i.e. queue the balloon tips
if (newState.Num != prevState.Num) {
Form1 form = new Form1("NumLock", newState.Num);
} else if (newState.Caps != prevState.Caps) {
Form1 form = new Form1("CapsLock", newState.Caps);
} else if (newState.Scroll != prevState.Scroll) {
Form1 form = new Form1("ScrollLock", newState.Scroll);
}
// Set the previous lock state to the new one in prep for the next iteration
prevState = newState;
// Sleep for 500ms
Thread.Sleep(500);
}
} catch (ThreadAbortException) { /* No need to do anything, just catch the ThreadAbortException.*/ }
}
}
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1("NumLock", true));
Application.Run(new FormApplicationContext());
}
}
}
Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyboardIndicators {
public partial class Form1 : Form {
public Form1(String activatedModifier, bool lockState) {
InitializeComponent();
ShowForm(activatedModifier);
//this.Show();
//this.Hide();
}
public void ShowForm(String activatedModifier) {
PictureBox pictureBox = new PictureBox();
Image myBitmap = Image.FromFile("cube.png");
Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);
switch (activatedModifier) {
case "NumLock":
break;
case "CapsLock":
break;
case "ScrollLock":
break;
}
this.Size = bitmapSize;
pictureBox.ClientSize = bitmapSize;
pictureBox.Image = myBitmap;
pictureBox.Dock = DockStyle.Fill;
this.Controls.Add(pictureBox);
this.FormBorderStyle = FormBorderStyle.None;
}
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
}
}