How to get system tray functionality WITHOUT using NotifyIcon.ContextMenu? - c#

I'm trying to get my application to display a popup context menu when a user right-clicks on my notify icon in the system tray... but there's a twist.
I'm aware that the NotifyIcon class I'm using to get the icon in the system tray has a ContextMenu property. I don't want to use that to get a right-click popup menu, because it ALWAYS displays a right-click popup menu, and never does anything else. When my main form is displaying a modal dialog, I want right-click to activate the main form, NOT display a popup menu.
So, I'm guessing I need to use the NotifyIcon.MouseClick event, and manually pop up the menu in that event? Here's where I've got to so far:
private NotifyIcon trayIcon;
private ContextMenu iconMenu;
private void frmMain_Load(object sender, EventArgs e) {
// [...]
this.trayIcon.MouseClick += new MouseEventHandler(trayIcon_MouseClick);
iconMenu = new ContextMenu();
// [...]
}
private void trayIcon_MouseClick(object sender, MouseEventArgs ea) {
this.iconMenu.Show(Program.instanceFrmMain, new Point(System.Windows.Forms.Cursor.Position.X - Program.instanceFrmMain.Left, System.Windows.Forms.Cursor.Position.Y - Program.instanceFrmMain.Top));
}
Notice how in iconMenu.Show, because it takes popup co-ordinates relative to the parent control (my main form here), I'm annoyingly having to subtract the parent control's co-ordinates from popup co-ordinates, something I already don't want to have to do.
Apart from that, here are the problems I'm having:
Although the menu does popup on right-click, it doesn't close if I click somewhere else on the screen outside the menu - and it should.
The menu doesn't quite popup in the right location; for other system tray apps, it pops up so its bottom-right or bottom-left corner are at the tip of the mouse cursor. For mine, the popup menu is at the base of the screen, to the side of the mouse cursor.
Any ideas how I can get this to work better? I know it's possible, plenty of other apps manually handle the displaying of a popup menu manually instead of using some NotifyIcon.ContextMenu property.

Use the ContextMenuStrip property rather than ContextMenu. The ContextMenuStrip class has an Opening event, which you can cancel by setting e.Cancel = true. That way you don't have to worry about the location of the menu, since it is automatically handled

OK, well I didn't manage to get the functionality I wanted as I described in the original question, but I have managed to find a way to achieve the desired effect using a different method.
I DO attach a ContextMenu to the trayIcon.ContextMenu property, but I attach event handler code to the Popup property of the context menu itself. If, in that handler, I .Clear the ContextMenu, it actually doesn't appear at all, allowing my code to elect to effectively stop the trayicon's popup menu from showing if it wants to. This was the effect I was looking to achieve. If I populate the ContextMenu in the Popup event handler code instead, the menu pops up as usual containing what I populated it with.
Sooo, I managed to solve the problem a different way. :-)

Related

What is the event which fires every time when i click outside for my wpf page?

i am developing windows application using wpf. I want to do some functionality when i click outside of my control created. for example, if i have Message-box open in my window, i want to do some function if i click outside of my Message-box window.
I tried,
private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
.....
}
but its not working.. please any one tell me, what is the event fire when i click outside of my control?
you have two supposed solutions:
one of them is to get Mouse.X, Mouse.Y from System not from application, this article will help
http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
second which is better is not using Dialog, but use PopUp window and this article will help
how to close a WPF Dialog Window when the user clicks outside it

Adding Click Handler On UserControl Breaks Click On Children

I have a user control that I'm trying to make draggable. The whole control should be draggable except when you click on buttons or text boxes. I'm handling the mousedown, mouseup and mousemove events on the usercontrol itself and I can drag by clicking anywhere. The only issue is now I can't click any buttons on the user control. Any clue what's going on?
Code is something like this:
<UserControl PreviewMouseLeftButtonDown="Popup_PreviewMouseLeftButtonDown" ....STUFF...>
<!-- CAN'T CLICK THIS -->
<Button />
<UserControl>
Code Behind:
public void Popup_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e)
{
mouseDown = true;
oldMousePosition = this.PointToScreen(e.GetPosition(this));
this.Popup.Child.CaptureMouse();
}
The issue arises when you use CaptureMouse() - this permanently captures all your mouse input on the window, and makes it so that you're unable to click on anything within the Window. I don't know if it's different for you, or if you checked, but it's not (just) that the Button is unclickable - it's that literally everything on the Window is unclickable.
You have to actually do something with the mouse after you've captured it, and then once you finish that, you have to return normal control by calling Mouse.Capture(null). For you, this would probably be best to do in your MouseUp() method.
However, this still leaves the child problem. I can't really think of any way you're going to be able to both capture all mouse click events on a parent control and allow them to get to the child control. I suppose you could check the mouse position against the button position, both relative to the UserControl, then route the click event to the Button every time, but this seems a little overelaborate. Is there a reason you can't just add a full-sized Grid to the UserControl with a lower ZIndex than the Button, and just use that to detect if a click was made inside the UserControl but not on the Button?

Click on form does not click underlying control

I have a windows forms application. When I click on a window this activates the form and then I need to click again to call the particular control click event. For example if I click on a button this activates the form and then I need to click the button again.
Is there a way to perform the control click and window activation in one click? Preferably I would want this to work with whatever the clickable control is (menu,button, label etc)
So far I have managed to activate the win form on mouse over and then the control click works. I would like to have the win form activated on click and also run the click command on an underlying control if this has a click event.
Well, here's a way to accomplish what You want (just attach a similar method to Your from's MouseClick event):
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
var c = this.GetChildAtPoint(e.Location);
this.InvokeOnClick(c, e);
}
This method has it's drawbacks though - for example the control will be clicked even though it's disabled etc., so You have to make sure the control under the cursor is "clickable" by yourself...

Interacting with a form without it activating

I'm trying to implement code-completion popup window in my project. The window is derived from Form. It contains two controls: custom list derived from UserControl (it shows completion possibilities with icons) and a VScrollBar.
When the popup appears, it doesn't steal focus from the editor (form's ShowWithoutActivation is overriden to return true) and the editor sends certain keystrokes to the popup so the user can interact with it using keyboard. So far it works like a charm.
The problem is, I want to allow the user to use mouse as well. But, when the user clicks into the popup window, its form activates and steals focus from the editor. I can react to this by giving the focus back to the editor, I have even set up a Timer to do this regularly, but apart from being a poor solution, the title bar of the editor always flickers when this happens (when the popup is clicked).
Is there any way to interact with the popup form (using mouse) that doesn't make the form activate?
The ShowWithoutActivation's documentation reads: "If your non-activated window needs to use UI controls, you should consider using the ToolStrip controls, such as ToolStripDropDown. These controls are windowless, and will not cause a window to activate when they are selected." This seems exactly like the thing I need, but I want to use a custom control and a scroll bar.
The same problem would be with a tooltip that shows these two arrows to switch method overloads (known from VS) - the whole form would use no controls at all (only render the text and the arrows), but when clicked, it should not activate. The problem could be summarized up to "How to create a form that would never activate, but allow the user to interact with certail controls inside?".
Thanks.
Just override the onFocus event...
public partial class myListBox:ListBox
{
protected override void OnGotFocus(EventArgs e)
{
}
}
The issue is that you're using a Form for this rather than building some custom control that doesn't run in its' own UI thread like a Form does.
The flashing and highlighting is handled by windows whenever a Form activates/focuses. The only thing I cay think of is to make your Form borderless and create/draw/handle your own title bar that doesn't flash when focused.
OK, I may have found a solution. The key seems to be WM_MOUSEACTIVATE message, which the popup form must intercept and respond with MA_NOACTIVATE. But there's a catch - the control derived from UserControl still grabs focus when clicked (the scrollbar luckily doesn't anymore). The problem seems to be in the UserControl.OnMouseDown method, which internally puts focus on the control. There are some ways to fix this:
derive the control from Control instead of UserControl
override the OnMouseDown method and not call base.OnMouseDown there
make the control's CanFocus property return false, but this seems not possible, because that means to make the control either not visible or not enabled, which is both undesirable
The last case when the popup form steals focus seems to be when its resizing (using mouse) ends. But it is safe here to call Owner.Activate() as a result to Activated event...

How to do two things with one click in Windows Form

On my main form, there is another (floatable) window. This floatable window works sort of like a popupwindow in that it will close when the user clicks somewhere else outside of this window. This is handled by the Deactivate event. But what I want to do is, if the user clicks on a different control (say a button), I want to both close this float window and then activate that button with just one click. Currently, the user has to click twice (one to deactivate the window and once more to activate the desired button). Is there a way to do this with just one click?
foreach(Control c in parentForm.Controls)
{
c.Click += delegate(object sender, EventArgs e)
{
if(floatyWindow != null && floatyWindow.IsFloating)
{
floatyWindow.Close();
}
};
}
And then add your handlers as normal. This additional handler can close the floaty window.
Make sure you floaty window isn't a dialog too as this will not allow your parent form's controls to be clicked.
I had a slightly hacky solution. In your Deactivate event, fire another custom event to your main form. Then when you main form is handling the custom event, enumerate through your control(this.Controls) and locate the control under the mouse by checking all their bound then call Focus(). You might need to sort by the one with the smallest surface area, or you can have a separate list of "focus-able" control like button just for this purpose.
Another way might be to switch focus to your main form immediately after OnMouseLeave of the floatable window, or OnMouseHover of your main window, but keep the floatable windows on top, just no focus. Handle the global mouse down of your main form, and close the floatable window by then.
These are just theories, not tested.
I had an issue like this once too, when a customer wanted "floaty" windows all over there application. I used used an approach similar to the one described in this article:
http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/article.asp
Code sample available here:
http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/Popup_Form_Demonstration.asp
By extending this a bit we created "floaty" windows similar to the ones VS uses when you get a runtime error while debugging code.
At the very least reading the code may give you some insight, however, quarrelsome's response may be the more simple solution.

Categories