Minimizing an application into tray [duplicate] - c#

I am finished making my application and now I want to incorporate " minimizing into the system tray feature " for it . I read up a good article minimize app to system tray . I realized that these make use of the Windows.Form class .
Unfortunately I have used Windows Presentation Foundation WPF reference to make my applications UI . Now I see that the NotifyIcon is not supported in WPF. I see that there is an open source library on CodePlex that simulates the NotifyIcon properties WPF Contrib I have not used it as yet .
Now I am in a fix . Here are my questions :-
a) I don't want to incorporate a 3'rd party library just for one single component .
b) Can I do the minimizing feature without NotifyIcon on WPF? If yes then how can someone give me leads please ?
Or maybe I should revert my UI back to using Windows Forms ?

If you'll reconsider your reluctance to using an external component, I recommend WPF NotifyIcon. I've used it. It's straightforward and works well.
It does not just rely on the corresponding WinForms component, but is a purely independent control which leverages several features of the WPF framework in order to display rich tooltips, popups, context menus, and balloon messages.

I just came across this post today.
For reference, I also solved this some time back. It works very well and the only time I have had a bit of an issue is occasionally on some multi-display set ups.
This was before GITs and NuGets were the in-thing, I will place it in a GIT repo if there is interest.
CodeProject Article Here

Solution with System.Windows.Forms.NotifyIcon
Here is a thread , which helped me a lot .
https://stackoverflow.com/a/12428063/10305444
public partial class Window : System.Windows.Window{
public Window()
{
InitializeComponent();
System.Windows.Forms.NotifyIcon ni = new System.Windows.Forms.NotifyIcon();
ni.Icon = new System.Drawing.Icon("Main.ico");
ni.Visible = true;
ni.DoubleClick +=
delegate(object sender, EventArgs args)
{
this.Show();
this.WindowState = WindowState.Normal;
};
}
protected override void OnStateChanged(EventArgs e)
{
if (WindowState == WindowState.Minimized)
this.Hide();
base.OnStateChanged(e);
}}

Related

Black areas on inherited ToolStrip [duplicate]

I use StatusStrip that contains ToolStripStatusLabel. OS - Windows 7, framework 2.0.
Usually all displayed normal, but sometimes ToolStripStatusLabel looks like black box:
I read that windows bug, but how I can fix it?
This is an obscure bug, triggered when you display the form with the Windows toolbar overlapping your StatusStrip. Moving the window away from the toolbar doesn't get the ToolStripItems on the status strip repainted properly. You'll find a bit of background in this forum post. There was a weak promise for a future fix for it, no idea if that ever happened. Probably not if you are running this on Win7.
You'll need to pay more attention to the position of the window, making sure that parts of it don't disappear underneath the toolbar. In general something you'd always consider, extra important as long as this bug doesn't get fixed. If you don't want to nail down the startup position (you ought to, users tend to like a window getting redisplayed where they last moved it) then simply change the form's StartPosition property to "CenterScreen".
This bug has never been fixed. It was in framework 2 and is still in framework 4.
The answer from Hans is a copy of the answer in social.msdn.microsoft.com.
But it is not helpful for me because "CenterScreen" does not solve the problem.
The cause of the problem is not the Windows Taskbar. The cause is a bug that does not draw the StatusStrip when the main Form is behind ANY other window at the first moment of drawing the StatusStrip. But this will also happen when you start the new process with Process.Start() from another process and the new process opens behind the window of another process.
I found a much better solution than the one proposed by Microsoft.
First I tried with
statusStrip.Invalidate();
but it does not work. So we need a stronger way to force Windows to redraw the StatusStrip. Important: The redrawing must happen when the Form with the StatusStrip is ALREADY in foreground! This is so easy that I don't understand why Microsoft does not suggest this method.
Timer mi_StatusTimer = new Timer();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
mi_StatusTimer.Interval = 500;
mi_StatusTimer.Tick += new EventHandler(OnTimerBugFix);
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
mi_StatusTimer.Start();
}
void OnTimerBugFix(object sender, EventArgs e)
{
mi_StatusTimer.Stop();
statusStrip.Hide();
Application.DoEvents();
statusStrip.Show();
}

VSTO splash screen or progress bar

I have a project that I'm doing with
Microsoft VSTO (office 2013 excel)
I have certain things that make calls that take maybe 10 seconds to come back.
Ideally I would like to display an progress bar or some status... After a lot of searching I found an article that is titled:
How do I create a splash screen window for the VSTO applications?
http://www.datazx.cn/Fv7p5a/xw/oa2v/2q7xs6/mcccjfti-988m-f8r8-8d44-bstb4rfsi4xm23rsdfd.html
So I started creating this code in a form, but then I realize that I need to call it up within my methods and really attach events etc...
The article says to
"display a modal form on a background thread" What is the best way to do this?
I find it easier to use modal less form on main thread and so far haven't seen any problem with modal less approach. Something like code below
var splashWindow = new SplashWindow();
splashWindow.Show();
splashWindow.SetMessage("Starting please wait...");
DoSomeWork(splashWindow);
splashWindow.Close();
Following you will see a way I programmed a Splash Screen for Excel-VSTO in C#. My Excel file is enabled for macros (.xlsm). These are the steps:
Create your splash screen. Let's assume the name of the form is SplashScreen.
Go to the code of the object ThisWorkbook.cs
Check the code looks like:
public partial class ThisWorkbook
{
SplashScreen SC = new SplashScreen();
private async void ThisWorkbook_Startup(object sender, System.EventArgs e)
{
SC.Show();
await Task.Delay(3500);
SC.Close();
more code...
}
}
It is important that you notice that I added the word async to the subroutine.
private void ThisWorkbook_Startup(object sender, System.EventArgs e)
I hope this is very useful.

Strange Bug with .NET 4.0/4.5 WinForms MenuStrip Stealing Focus

We recently upgraded to VS 2012 which is accompanied by an upgrade to .NET Framework 4.5. This introduces a strange and pesky bug in connection with WinForms MenuStrip control. The same bug also occurs in applications targetting .NET Framework 4.0 as 4.5's installer obviously updates parts of 4.0 as well. Therefore, a perfectly working code pattern is now broken just because of the framework upgrade.
Problem description:
I have a Form1 with a MenuStrip. For one of the drop down items, the event handler opens another Form2 (not neccessarily a child, just another Form). If the user right-clicks into the new Form2 or one of its child controls and this triggers a Show() of a ContextMenuStrip, then the original Form1 pops into foreground again.
This happens independent of all previous other UI actions in Form2. One can resize, move, minimize, maximize Form2, switch between controls, enter text etc. Somehow MenuStrip of Form1 seems to remember that it caused opening of Form2 and grabs focus on first right-click.
I was experimenting with different approaches but was unable to find a workaround so far. The constellation is not uncommon and might affect lots of WinForms applications around. Therefore I decided to post it here since a viable solution might be of general interest. I would be very glad if someone knows a workaround or has at least some clues for me.
I was able to distill it's essence in the following code. It should be reproducible on any machine with .NET 4.5 installed and it occurs when targetting 4.0 and 4.5 each - but not on 3.5 or lower.
using System;
using System.Windows.Forms;
namespace RightClickProblem {
static class Program {
[STAThread]
static void Main() {
// Construct a MenuStrip with one item "Menu" with one dropdown-item "Popup"
var mainMenu = new MenuStrip();
var mainItem = new ToolStripMenuItem("Menu");
mainItem.DropDownItems.Add(new ToolStripMenuItem("Popup", null, Popup));
mainMenu.Items.Add(mainItem);
// Create form with MenuStrip and Show
var form1 = new Form();
form1.Controls.Add(mainMenu);
Application.Run(form1);
}
private static void Popup(object sender, EventArgs e) {
// Create a form with a right click handler and show
var form2 = new Form();
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("Just an item...");
form2.ContextMenuStrip = contextMenu;
form2.Show();
// Problem: contextMenu.Show() will give focus to form1
}
}
}
EDIT: I spent some time stepping through .NET Framework source code and found the root cause to be very likely in System.Windows.Forms.ToolStripManager. There, Microsoft is using a message filter to track window activation which is somehow incorrectly implemented for MenuStrip.
In the meantime I also found that Microsoft already adressed this issue in a hotfix (see http://support.microsoft.com/kb/2769674) and hopefully this will find its way into a future update of .NET Framework 4.5.
Unfortunately it is difficult to enforce this hotfix to be applied on all client machines. Therefore a viable workaround would still be greatly appreciated. I myself have been unable so far to find a practical solution...
EDIT#2: The original KB number is for Win8 but there is similar Hotfix for Win7 & Vista under KB 2756203. If somebody can use it, found the hotfix for download here: http://thehotfixshare.net/board/index.php?autocom=downloads&showfile=15569. We tested it and it really fixes the problem. If we find definitely no workaround soon, we'll go with the hotfix.
EDIT#3: Remarks to the accepted solution proposed by spajce
Obviously calling Show() on any ContextMenu will convince the original MenuStrip to forget about its claim on focus. This can be done in a way so that the dummy ContextMenu is not even shown on screen. I found the shortest and most easy to implement way to insert the following snippet in any Form's constructor:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
using (var dummyMenu = new ContextMenuStrip()) {
dummyMenu.Items.Add(new ToolStripMenuItem());
dummyMenu.Show(Point.Empty);
}
}
}
So every Form that opens cleans up the corrupted state of the ToolStripMenu system. One might as well put this code in a static method like FormHelper.FixToolStripState() or put it in OnCreateControl(...) of a template Form and inherit all Forms from that (what is what we luckily do anyway).
this is my solution :)
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// Construct a MenuStrip with one item "Menu" with one dropdown-item "Popup"
var mainMenu = new MenuStrip();
var mainItem = new ToolStripMenuItem("Menu");
mainItem.DropDownItems.Add(new ToolStripMenuItem("Popup", null, Popup));
mainMenu.Items.Add(mainItem);
// Create form with MenuStrip and Show
var form1 = new Form();
form1.Controls.Add(mainMenu);
Application.Run(form1);
}
private static void Popup(object sender, EventArgs e)
{
// Create a form with a right click handler and show
var form2 = new Form();
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("Just an item...");
var loc = form2.Location; //<---- get the location
var p2 = new Point(loc.X, loc.Y); //<---- get the point of form
form2.ContextMenuStrip = contextMenu;
form2.ContextMenuStrip.Show(form2, p2); //<---- just add this code.
form2.Show();
// Problem: contextMenu.Show() will give focus to form1
}
}
I was having this problem too. I didn't want to change code, because I felt my program was doing it right. I found the fix here on Microsofts website:
http://support.microsoft.com/kb/2750147
It does make a difference and we just installed it on 2 user computers this morning. Our IT guy is installing it on all the computers today now that it has been tested and shown to work.

Is it absolutely safe to display a WPF window from a WinForms form?

I would like to display a WPF window from a windows forms application (.NET 3.5).
This code seems to work without any problem in a sample project:
public partial class WinFormsForm1 : Form
{
public WinFormsForm1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
WpfWindow1 w = new WpfWindow1();
w.Show();
}
}
The form is started from Main() as a normal Winforms form:
Application.Run(new WinFormsForm1());
This seems to me too easy to be true. Are there any shortcomings in this? Is this safe to do?
It has one serious shortcoming: the modeless WPF window would not get keyboard input.
The EnableModelessKeyboardInterop method call needs to be added before the WPF window is shown:
WpfWindow1 w = new WpfWindow1();
System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(w);
w.Show();
ElementHost resides in WindowsFormsIntegration.dll.
Further reading: http://msdn.microsoft.com/en-us/library/aa348549.aspx
Bottom line: it is.
We have pretty heavy application combining both WPF and winforms: windows, user controls, modal dialogs, you name it... and it's working in the medical market.
We've got into some dark corners, one is the infamous EnableModelessKeyboardInterop, another is having the WPF window be the child of the Winforms window, which you can read Here
It is really that simple. I can't think of any downside doing it this way.

Alternative to TextViewCreated such as (TextViewChanged)?

I am creating a small Visual Studio 2010 extension in C# which uses the IWpfTextViewCreationListener and TextViewCreated to capture when a new TextView is opened in the VS environment. The problem I am having is that this method only fires when a new window is opened via the VS Solution Explorer window, and not fired when VS already contains opened windows when started, and switching window tabs. I have tried looking for something like TextViewChanged, but could not find such method. Is there anyway to capture the new TextView when another tabbed window is selected?
Any help would be greatly appreciated.
This question has also been posted on the MSDN VS Extensibility forum:
VSX 2010 - Alternative to TextViewCreated such as (TextViewChanged)?
Thanks
John
There is no TextViewCreated, but if you register to IWpfTextView.GotAggregateFocus as it is created, you get a hook to every switch between files:
public void TextViewCreated(IWpfTextView textView)
{
textView.GotAggregateFocus += TextViewCameToFocus;
// Do stuff when a new IWpfTextView is created...
}
void TextViewCameToFocus(object sender, EventArgs e)
{
var focusedTextView = (IWpfTextView)sender;
// Do stuff when a specific IWpfTextView comes to focus...
}
You may also want to keep track of the IWpfTextView objects, if you want to be able to link between the fired events to your logic of each textview.

Categories