I'm making a simple CPU Usage monitor. The application is just an icon in the task bar which uses the Microsoft.WindowsAPICodePack library to display the CPU Usage of a task as an icon progress bar.
This application is currently working fine. For added value, I want to prevent the user from opening the application's form, which is blank. Currently I'm using the following code:
/// <summary>
/// Forces this window to remain minimized.
/// </summary>
private void MainForm_SizeChanged(object sender, EventArgs e)
{
if (WindowState != FormWindowState.Minimized)
WindowState = FormWindowState.Minimized;
}
This causes the form to flash on the screen for an instant and shrink back to the task bar. I'd prefer for absolutely nothing to visibly happen when the icon is clicked. Is there a way to achieve this?
Attempt 1
Following deathismyfriend's advice, I tried to hide the form. The WindowsAPICodePack throws an exception:
A valid active Window is needed to update the Taskbar.
Attempt 2
Setting this.Opacity = 0 didn't quite work. Funnily enough, the form is transparent... until you minimize it. Then it appears and shrinks to the task bar.
This worked for me. Trap WM_SYSCOMMAND and suppress SC_RESTORE / SC_MAXIMIZE:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Opacity = 0; // prevent ALT-TAB preview
this.WindowState = FormWindowState.Minimized;
}
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_RESTORE = 0xF120;
const int SC_MAXIMIZE = 0xF030;
if ((m.Msg == WM_SYSCOMMAND) && ((int)m.WParam == SC_RESTORE || (int)m.WParam == SC_MAXIMIZE))
{
return;
}
base.WndProc(ref m);
}
}
*Setting Opacity() to 0 (zero) did prevent the Alt-Tab preview window.
You are going against Windows interface standards to do this. That's why it is hard. The system tray is built for this type of application. You still should be able to animate an icon in the system tray to show this sort of information. Here's another question that helps with the system tray:
How can I make a .NET Windows Forms application that only runs in the System Tray?
Still not elegant, but you could set your FormBorderStyle to FormBorderStyle.None to prevent the right-click context menu on the window preview in aero and then move the form off screen:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Location = new Point(int.MinValue, int.MinValue);
}
Set the opacity to 1 and put the window in an offscreen location. The form will still flash, but will be invisible to the user.
Related
I am already aware that using ShowDialog() can cause the form to go behind to its parent form. So I look for a solution.
Many says that the solution is to pass the parent form as a parameter to the child form.
Something like this.
using(Form f = new Form1())
{
f.ShowDialog(this);// while the 'this' is the parent form calling
}
but this code still fails.
This is the scenario.
Open the child form showing the dialog, then when the child form window is still active, click show desktop (or press Window+D) then, open other application.
after opening the application minimize it or close it. now after you close or minimize the other application.
Now the child form is already behind the parent form. now you should press alt+tab or click it form the taskbar to work it again properly.
I will appreciate for any help.
Good question. It seems like then the child dialog is visible, and Windows+D is pressed, the parent form ignores the request (or possibly the OS prevents sending a minimize request to the parent form because it has an active modal dialog). Just guessing. The parent form is never sent a minimize message.
You can observe this by using TOOLS -> Spy++ and notice the lack of window messages sent to the parent window when the child dialog is showing and Windows+D is pressed. The messages received are in the orange box:
That means the parent form is never actually minimized. Windows stops painting it, but opening another window turns the painting back on.
So using the WM_ACTIVATEAPP as a reference point, force the parent form to be minimized. This has the side effect that the child dialog is made invisible. Then listen for the SC_RESTORE message, and reshow the child dialog:
public class RestoreForm : Form {
private const int SC_RESTORE = 0xF120;
private const int WM_SYSCOMMAND = 0x0112;
private const int WM_ACTIVATEAPP = 0x1C;
public RestoreForm() {
Button btn1 = new Button { Text = "ShowDialog(...)", AutoSize = true };
btn1.Click += btn1_Click;
Controls.Add(btn1);
}
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if (f2 != null) {
if (m.Msg == WM_ACTIVATEAPP) {
if (f2.WindowState == FormWindowState.Minimized) {
this.WindowState = FormWindowState.Minimized;
}
}
else if (m.Msg == WM_SYSCOMMAND) {
var w = m.WParam.ToInt32();
if (w == SC_RESTORE) {
f2.WindowState = FormWindowState.Normal;
//f2.Visible = true; // ignores staying on top of previous parent
f2.ShowDialog(this);
}
}
}
}
Form f2 = null;
void btn1_Click(object sender, EventArgs e) {
f2 = new Form { Text = "Child" };
f2.ShowDialog(this);
}
}
My closest workaround to solve this is set ShowInTaskbar and MinimizeBox to false.
Actually I can just disable ShowInTaskbar without disabling the minimize box, but there is no point, allowing the user to minimize the child form but still they cant perform any action on the parent form.
I have an application that I am working on (for myself), and I want to prevent the Window from showing at all.
So far, what I have got is WindowState.Minimized so that the Form's initial state is Minimized. And when I click the app's icon in the Taskbar, I want it to remain minimized - not just Hide() it when it has shown. So I thought that something like this might work:
protected override void OnGotFocus(EventArgs e)
{
this.WindowState = WindowState.Minimized;
}
But I was wrong. So what I am thinking is that I need something that happends before OnGotFocus. The reason that just hiding it when it gets focused is not enough, is because you can see, very faintly, that it does actually show itself when you click the icon in the taskbar before this.WindowState = WindowState.Minimize gets called.
My only requirement is that the application must not be shown when it's icon is clicked on the Taskbar. I will need to show the window programatically, at some point, though.
How can I make sure that clicking its icon never shows the window?
This seemed to work for me with no "hint" of it coming and going:
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0112) //WM_SYSCOMMAND
{
if ((m.WParam.ToInt32() & 0xFFF0) == 0xF030 ||
(m.WParam.ToInt32() & 0xFFF0) == 0xF120)
m.WParam = new IntPtr(0xF020);
}
base.WndProc(ref m);
}
Just override the WndProc and this will catch both SC_MAXIMIZE (0xF030) and SC_RESTORE (0x0F120). SC_MINIMIZE is 0xF020.
As Hans has suggested, I have edited my post to mask out the low-order bits used by the system per this MSDN section: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx
Hi you can use the form_resize event to trigger windowstate to minimized
private void Form1_Resize ( object sender , EventArgs e )
{
if ( WindowState == FormWindowState.Maximized )
{
// minimize it here
}
}
Firstly, I have zero experience programming with .NET so this could be a pretty nooby question...
I'm wondering if it's possible to build an application like xFire - which displays pop-ups in-game to a user.
As the primary application will have focus, how does my application manage to display it's message/popup? Does the primary application have to allow access or something?
Cheers!
Looks like you are looking for NotifyIcon, it displays little pop-ups just as know from Windows.
The example is a little long, but the documentation will surely help you understand.
using System;
using System.Drawing;
using System.Windows.Forms;
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.NotifyIcon notifyIcon1;
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.ComponentModel.IContainer components;
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
public Form1()
{
this.components = new System.ComponentModel.Container();
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
// Initialize contextMenu1
this.contextMenu1.MenuItems.AddRange(
new System.Windows.Forms.MenuItem[] {this.menuItem1});
// Initialize menuItem1
this.menuItem1.Index = 0;
this.menuItem1.Text = "E&xit";
this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
// Set up how the form should be displayed.
this.ClientSize = new System.Drawing.Size(292, 266);
this.Text = "Notify Icon Example";
// Create the NotifyIcon.
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
// The Icon property sets the icon that will appear
// in the systray for this application.
notifyIcon1.Icon = new Icon("appicon.ico");
// The ContextMenu property sets the menu that will
// appear when the systray icon is right clicked.
notifyIcon1.ContextMenu = this.contextMenu1;
// The Text property sets the text that will be displayed,
// in a tooltip, when the mouse hovers over the systray icon.
notifyIcon1.Text = "Form1 (NotifyIcon example)";
notifyIcon1.Visible = true;
// Handle the DoubleClick event to activate the form.
notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick);
}
protected override void Dispose( bool disposing )
{
// Clean up any components being used.
if( disposing )
if (components != null)
components.Dispose();
base.Dispose( disposing );
}
private void notifyIcon1_DoubleClick(object Sender, EventArgs e)
{
// Show the form when the user double clicks on the notify icon.
// Set the WindowState to normal if the form is minimized.
if (this.WindowState == FormWindowState.Minimized)
this.WindowState = FormWindowState.Normal;
// Activate the form.
this.Activate();
}
private void menuItem1_Click(object Sender, EventArgs e) {
// Close the form, which closes the application.
this.Close();
}
}
See MSDN.
"As the primary application will have focus, how does my application manage to display it's message/popup? Does the primary application have to allow access or something?"
An application can set itself as "TopMost" which means it appears in front of other "normal" applications that are not TopMost. A well behaved notification will appear without stealing focus from the current application (this is usually achieved with the ShowWindow() API and the SW_SHOWNA flag). This does not require any permission from the currently active application.
Take a look at TaskbarNotifier, a skinnable MSN Messenger-like popup in C# and now in VB.NET too.
When I click minimize button in my Windows Forms application, I don't want it to perform the classic Windows minimize animation (window going down to taskbar).
As far as I know, there's no Minimize event, I can just use Resize, but I have no clue how to detect if I clicked minimize button. I tried to use if ( WindowState = FormWindowState.Minimized ) { ... }, but that does the animation anyway and triggers the code after.
Is there any way to detect minimize button click? Is there any way to disable animations or is that triggered by Windows settings?
This works, but it has an unpleasant side-effect on the taskbar button. I can't think of another way, animation isn't even accessible from SystemParametersInfo().
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void WndProc(ref Message m) {
// Catch WM_SYSCOMMAND, SC_MINIMIZE
if (m.Msg == 0x112 && m.WParam.ToInt32() == 0xf020) {
this.Hide();
this.WindowState = FormWindowState.Minimized;
this.BeginInvoke(new Action(() => this.Show()));
return;
}
base.WndProc(ref m);
}
}
Update: disabling animation on Aero is possible by pinvoking DwmSetWindowAttribute() with the DWMWA_TRANSITIONS_FORCEDISABLED attribute. See this answer.
Ok heres my problem. I have a form that when it is not maximised, its maximum size has to be the total height of the components inside the form. To achieve this, i use this:
private void resize_form(object sender, EventArgs e)
{
this.MaximumSize = new System.Drawing.Size(1000, this.panel4.Height + this.label2.Height + this.HeightMin);
}
That fires on the Resize event of the form. Because the component size is always changing it made sense to do this on a resize event. How ever if i want to maximise the form, the form just goes to the highest settings defined in this.MaximumSize. So i was wondering is there a way to tell when a form is going to be maximised and set its maximumsize to the screen boundarys before the form maximises.
If there is a better way to change the maximumsize value without resize event, that would also be great :)
You still need to use the resize event, but check the WindowState:
if (this.WindowState == FormWindowState.Maximized)
{
// Do your stuff
}
As yshuditelu points out you can set the minimum size property of your form too - which should, when coupled with judicious use of anchor values, mean that it can never shrink too far and when it does grow the components will move and/or grow as required.
I found the answer that suited me perfectly. A lil WndProc override :D (i love WndProc now)
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MAXIMIZE = 0xF030;
switch (message.Msg)
{
case WM_SYSCOMMAND:
int command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MAXIMIZE)
{
this.maximize = true;
this.MaximumSize = new System.Drawing.Size(0, 0);
}
break;
}
base.WndProc(ref message);
}
private void resize_form(object sender, EventArgs e)
{
if (!maximize)
{
this.MaximumSize = new System.Drawing.Size(1000, this.panel4.Height + this.label2.Height + this.HeightMin);
}
}
Basically it sets this.maximize to true when it receives teh SC_MAXIMIZE message. The resize event will only set a new MaximumSize if this.maximize is set to false. Nifty xD
Are you sure you don't want to be setting the MinimumSize property? If you set the MinimumSize to the size of all the labels, then the form will never be smaller than that. But it can still grow to whatever size the user wants, so long as it is larger than the minimum.
Check out the System.Windows.Forms.Screen class. Get the screen from a relevant point (to handle the multi-mon case) and then get its resolution.
This should work in conjunction with the other comment about checking FormWindowState.Maximized.
If the user clicks in the upper bar, they can resize the window, so I use this:
private void Form1_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Normal)
{
this.WindowState = FormWindowState.Maximized;
}
}