Update (redraw) system-tray window after a button is removed [duplicate] - c#

This question already has answers here:
Tray icon does not disappear on killing process
(8 answers)
Closed 9 months ago.
After I send a TB_DELETEBUTTON message to delete a button (of a external application) in the system-tray toolbar, it remains a blank/empty rectangle from that deleted button, and the toolbar does not remove this empty rectangle until I do left or right click on some other icon, then finally the toolbar window gets redrawn and the empty rectangle from he button that I deleted disappears.
This is an aesthetic issue that I would like to avoid. I just would like to programatically update/redraw the toolbar window after I send the TB_DELETEBUTTON message, however after I call the UpdateWindow, UpdateLayeredWindow or RedrawWindow, the empty rectangle of the deleted button remains there.
The flags cobmination that I tried to use with RedrawWindow are: RDW_FRAME, RDW_ALLCHILDREN, RDW_UPDATENOW and RDW_INVALIDATE, all together.
The window handle that I'm passing to these functions is the window with class name: "ToolbarWindow32" (on which reside the system-tray buttons/icons of the applications), a example for getting this window handle can be found here.
My question is: how can I properly update/redraw this window?.

After calling the InvalidateRect function I noticed that the notification area window is redrawn (because the window flicks for a moment), so redrawing the window seems not a valid solution to solve this issue...
However, in the next thread I found a solution:
https://forum.lazarus.freepascal.org/index.php?topic=14847.0
The thing is that in order to "properly" refresh the size of the notification area to remove any empty space from previously deleted buttons, I just need to send WM_LBUTTONDOWN and WM_LBUTTONUP messages through the SendMessage function.
These window messages must be sent two times (at least for Windows 10) to the ToolbarWindow32 window following the next order: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDOWN, WM_LBUTTONUP. This is to reproduce two single clicks (not a double click) in the first button inside the system-tray, which is what I manually needed to do before applying this automated solution. After sending the messages, the window becomes "auto-sized" properly.
The only aesthetic problem would be if the first button is a button from an application that performs some undesired action when doing a single click on its button, but this is not typical to see. Typically the user only can do a double-click to restore the window from the button on system-tray, or do right click to open its context menu, but nothing should happens for doing a single click on a button... if the developer didn't programmed anything to happen.
Note that this methodology also works when there is the up arrow that contains "hidden" buttons.

Related

Winforms - discard unwanted double click

In my C# Winforms application I have a 'Welcome' window with a number of buttons. One of these is 'Exit' which closes the application. Other buttons replace the window with a task-specific window. All the task Windows have a 'Close' button which returns to the Welcome screen. Conventionally, the Close button is in the same place as the Exit button in the Welcome window.
The problem I have is that some users are trigger happy and double click on the Close buttons. The first click triggers the Close action, and the task window closes. But it would appear that the second click is being bufferred, and is given to the Welcome window once it is displayed, and results in the Exit button being clicked. This is NOT the desired behaviour!
Is there any way I can discard the unwanted second click on the Close button? The task windows raise an AppletClosing event back to the Welcome window when they are closing, so it would be easy to do it in that handler - if I knew what to do.
Thanks for any help - much appreciated.
Kevin

TextBox behaves differently when losing focus in different ways

The WinRT TextBox control has a delete button that shows up when the control has focus and there is text in it.
When the control loses focus by tapping outside of it or tabbing outside of it, the delete button disappears.
When the control loses focus by tapping in a different app (two apps are up in splitscreen), the delete button doesn't disappear.
Is there a way to detect the different lost focus events? Nothing from the sender or RoutedEventArgs is different in the two cases where the control loses focus.
You can handle Window.Activated to check if the whole app has lost focus:
This event occurs when a Window has been activated or deactivated by
the system. An app can determine what the status of the Window
activation is by checking the
WindowActivatedEventArgs.WindowActivationState property. A Window
could be visible on screen but not be active (for example, in snapped
apps). Additionally, if any other parts of the system takes focus away
from the window, this event will occur. This could happen as a result
of user interaction or code, and the WindowActivationState will
indicate which action has taken place.
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.window.activated.aspx

Close Modal Form when mouse click outside form area

I would like to close a modal form when the user clicks outside (anywhere on the computer desktop) the modal form. How can we do this as a modal form is not meant to lose focus.
You need to hook mouse (and keyboard if required) and capture their events. Then check if the click happened outside the form (and area). If yes, flag a sign which can be read by the model form that it can close down.
Algo:
Hook mouse click event.
When callback function is called, check for the click position - if it's inside your form or not (you might need to translate the locations to Desktop locations - I hope you know how to!)
If the point is outside the form, set a flag (boolean or anything that makes you happy). Make sure the form can read the flag somehow.
Trigger an event for form to capture. In it's handler read the flag status. If true, close/unload the form.
This page will tell you technical details and functions.
I don't think you need to make it modal... then you can take siride's option of closing it on the Deactivate event.
The reason you don't need to make it modal: The first time you display it, it will have the focus and be topmost. Modal prevents you from clicking somewhere else, but you want to be able to click somewhere else... and when you do, the form goes away, so there are no modal needs.

Show/Hide ContextMenuStrip outside the form

I'm creating a simple clipboard manager application. It monitors the content of a clipboard. When a change occurs (throu the win api message loop) it fires up a method to capture current content of clipboard and creates new object called clipboarditem. Next its building a ContextMeuStrip which consits of several clipboarditems created previously. The items menu is accessed by a hotkey. It shows up this menu on certain position of the screen itemsMenu.Show(caretPosition);, with .Focus(), I want it to make it disappear after it loses the focus (eg. clicking somehwere else on the screen or switch applications by alt-tab). Found an event OnLoseFocus but I dont think its working properly because the menu wont even show up.
How to make ContextMenuStrip disappear after loosing focus and how to prevent from showing ContextMenuStrip in taskabr ?
Sorry for my language skills :)
From a very quick look at the events that ContextMenuStrip contains, have you tried the "MouseCaptureChanged" event? It may help you with the losing focus issue.
For the showing in the taskbar issue, have you set "ShowInTaskbar" to false on the form you have your ContextMenuStrip (if you have it on a form)?

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