ContextMenuStrip.Show not working half the time - c#

tl/dr: Every second time I call ContextMenuStrip.Show, it doesn't show.
I am building an application that runs in the background but displays a drop-down menu on the mouse cursor when the user hits a specific hotkey.
If the application has focus, this works 100% of the time. If another application has focus (this is my main use case) it fails exactly 50% of the time. Specifically, the first hotkey press works, but once you select an item from the menu (which triggers a short function), the next hotkey press does not display the menu. If you keep pressing the hotkey without clicking the menu, the menu keeps popping up at the cursor position. If you switch back to the application, the menu appears every time.
I am fairly new to coding, but I have simplified the code such that the hotkey press does nothing other than run a single line of code (ContextMenuStrip.Show), and I have watched in the debugger and that line does get hit, and all the variables look the same to me on the presses that do and don't work.
EDIT: This is the simplest version of the code I could make. Please excuse any weirdness. I'm new to coding and am probably doing unrelated strange things!
To reproduce, run the program, switch to another window, press Ctl-Q to bring up the menu, select an item, press Ctl-Q again and the menu should fail to show.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
using System.Runtime.InteropServices;
namespace Bug
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Register hotkey
int UniqueHotkeyId = 1;
int HotKeyCode = (int)Keys.Q;
Boolean F9Registered = RegisterHotKey(
this.Handle, UniqueHotkeyId, 2, HotKeyCode
);
myPopupMenu.menu = myPopupMenu.BuildMenu();
}
// Stuff that makes the hotkey work
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
protected override void WndProc(ref Message m)
{
// Catch when a HotKey is pressed !
if (m.Msg == 0x0312)
{
int id = m.WParam.ToInt32();
if (id == 1)
{
// Show Menu on hoteky press
myPopupMenu.ShowMenu();
}
}
base.WndProc(ref m);
}
public PopupMenu myPopupMenu = new PopupMenu();
}
public class PopupMenu
{
public ContextMenuStrip menu { get; set; }
public ContextMenuStrip BuildMenu()
{
ContextMenuStrip menu = new ContextMenuStrip();
ToolStripMenuItem item;
ToolStripMenuItem submenu;
submenu = new ToolStripMenuItem();
submenu.Text = "submenu";
item = new ToolStripMenuItem("item", null, MenuClick);
submenu.DropDownItems.Add(item);
menu.Items.Add(submenu);
return menu;
}
public void ShowMenu()
{
menu.Show(Cursor.Position);
}
public void MenuClick(object sender, EventArgs e) { }
}
}

Change
ContextMenuStrip menu = new ContextMenuStrip();
To
ContextMenuStrip menu = new ContextMenuStrip { AutoClose = false };
And your example now works 100% of the time on my end (both focused and not focused).
Why, I'm not quite sure. Just used an automated tool to rapidly change things until desired behavior occurred.

Related

Why is ListView rendering so slow for certain characters?

Update 1: I've written both a MFC-C++ implementation and an old-school Win32 app and recorded a video demonstrating how bad the issue really is:
https://www.youtube.com/watch?v=f0CQhQ3GgAM
Since the old-school Win32 app is not exhibiting this issue, this leads me to believe that C# and MFC both use the same rendering API that must cause this issue (basically discharging my suspicion that the problem might be at the OS / graphics driver level).
Original post:
While having to display some REST data inside a ListView, I encountered a very peculiar problem:
For certain inputs, the ListView rendering would literally slow to a crawl while scrolling horizontally.
On my system and with the typical subclassed ListView with "OptimizedDoubleBuffer", having a mere 6 items in a ListView will slow down rendering during scrolling to the point that i can see the headers "swimming", i.e. the rendering of the items and headers during the scrolling mismatches.
For a regular non-subclassed ListView with 10 items, I can literally see each item being drawn separately while scrolling (the repainting takes around 1-2s).
Here's example code (and yes, I am aware that these look like bear and butterfly emotes; this issue was found from user-provided data, after all):
using System;
using System.Windows.Forms;
namespace SlowLVRendering
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
const string slow = "ヽ( ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ( ´。㉨°)ノ ༼ つ´º㉨º ༽つ ) (」゚ペ)」ヽ( ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ( ´。㉨°)ノ ༼ つ´º㉨º ༽つ ) (」゚ペ)」";
ListView lv = new ListView();
lv.Dock = DockStyle.Fill;
lv.View= View.Details;
for (int i = 0; i < 2; i++) lv.Columns.Add("Title "+i, 500);
for (int i = 0; i < 10; i++)
{
var lvi = lv.Items.Add(slow);
lvi.SubItems.Add(slow);
}
Controls.Add(lv);
}
}
}
Can someone explain what the issue is, and how to resolve it?
After trying a few different things, here is the fastest solution I found. There is still a little hesitation, but not anywhere near as your original solution. Until Microsoft decides to use something better than GDI+, it doesn't get better unless you go to WPF with .NET 4 and above. Oh well.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SlowLVRendering
{
[System.Runtime.InteropServices.DllImport("user32")]
private static extern bool SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
private uint LVM_SETTEXTBKCOLOR = 0x1026;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
const string slow = "ヽ( ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ( ´。㉨°)ノ ༼ つ´º㉨º ༽つ ) (」゚ペ)」ヽ( ´。㉨°)ノ Ƹ̴Ӂ̴Ʒ~ ღ ( ヽ( ´。㉨°)ノ ༼ つ´º㉨º ༽つ ) (」゚ペ)」";
ListView lv = new BufferedListView();
// new ListView();
//new ListViewWithLessSuck();
lv.Dock = DockStyle.Fill;
lv.View = View.Details;
for (int i = 0; i < 2; i++) lv.Columns.Add("Title " + i, 500);
for (int i = 0; i < 10; i++)
{
var lvi = lv.Items.Add(slow);
lvi.SubItems.Add(slow);
}
Controls.Add(lv);
//SendMessage(lv.Handle, LVM_SETTEXTBKCOLOR, IntPtr.Zero, unchecked((IntPtr)(int)0xFFFFFF));
}
}
public class BufferedListView : ListView
{
public BufferedListView()
: base()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
}
class ListViewWithLessSuck : ListView
{
[StructLayout(LayoutKind.Sequential)]
private struct NMHDR
{
public IntPtr hwndFrom;
public uint idFrom;
public uint code;
}
private const uint NM_CUSTOMDRAW = unchecked((uint)-12);
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x204E)
{
NMHDR hdr = (NMHDR)m.GetLParam(typeof(NMHDR));
if (hdr.code == NM_CUSTOMDRAW)
{
m.Result = (IntPtr)0;
return;
}
}
base.WndProc(ref m);
}
}
You can see for yourself the difference. If you uncomment the SendMessage and change new BufferedListView(); to new ListViewWithLessSuck(); You can see the change.
I believe I have narrowed the problem down to Visual Styles. Commenting out Application.EnableVisualStyles(); in static void Main results in a huge performance boost during scrolling, though nowhere near the performance of the Win32 app as shown in the video that I mentioned in Update 1.
The downside of this of course is that all controls in your application will look "old". I've therefore experimented with selectively disabling / enabling of visual styles through
[DllImport("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)]
public extern static Int32 SetWindowTheme(IntPtr hWnd, String textSubAppName, String textSubIdList);
and using Win32.SetWindowTheme(lv.Handle, " ", " "); as described in the MSDN docs. The most logical thing would be to keep Visual Styles active for most of the controls and turn if off for performance critical ones. However, a part of the ListView seems to deliberately ignore whether visual styles are disabled or enabled, namely the column headers of the listview in report mode:
(Note how the column header looks in comparison to the scroll bars)
So unless someone knows how to force visual styles off on listview column headers, this is a "pick your poison" kind of situation: Either comment out Application.EnableVisualStyles(); and have an ugly looking UI or leave it in and risk unpredictable renderer slowdowns.
If you go for the first choice, you can get another huge performance boost by subclassing the ListView and short-circuiting the WM_REFLECT_NOTIFY message (thanks to SteveFerg for the original):
public class ListViewWithoutReflectNotify : ListView
{
[StructLayout(LayoutKind.Sequential)]
private struct NMHDR
{
public IntPtr hwndFrom;
public uint idFrom;
public uint code;
}
private const uint NM_CUSTOMDRAW = unchecked((uint) -12);
public ListViewWithoutReflectNotify()
{
}
protected override void WndProc(ref Message m)
{
// WM_REFLECT_NOTIFY
if (m.Msg == 0x204E)
{
m.Result = (IntPtr)0;
return;
//the if below never was true on my system so i 'shorted' it
//delete the 2 lines above if you want to test this yourself
NMHDR hdr = (NMHDR) m.GetLParam(typeof (NMHDR));
if (hdr.code == NM_CUSTOMDRAW)
{
Debug.WriteLine("Hit");
m.Result = (IntPtr) 0;
return;
}
}
base.WndProc(ref m);
}
}
Disabling visual styles and subclassing allow for rendering speeds nearly on par of that of the Win32 C app. However, I do not fully understand the potential ramifications of shorting WM_REFLECT_NOTIFY, so use with care.
I've also checked the Win32 app and confirmed that you can literally kill the rendering performance of your app simply by adding a manifest, for example like so:
// enable Visual Styles
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")

Dynamic creation of forms & containers

I'm very new to C#.
Below is a code that I'm trying to create forms and containers within the code; but I've problems with it.
I start with a new Windows Forms Application template.
I change the Program.cs file a little, so that I'd be able to create the FormMain dynamically.
When the lines Container.Add(BtnClose) and BtnClose_Setup() in FormMain.cs are commented, the code compile and run. However, there are still some weird results in the program.
(a) The form FormMain is supposed to show up at (20, 20) (upper left corner), as the FormMain_Setup says; but when I run the app, though width & height settings show up as expected (800, 600), the upper left corner changes every time (does not stick to 20, 20).
(b) The esc key works as expected and closes the form and application.
When the lines Container.Add(BtnClose) and BtnClose_Setup() in FormMain.cs are not commented, the code compile but VS sends me a message when it's run: "An unhandled exception of type 'System.TypeInitializationException' occurred in mscorlib.dll"
Can someone tell me what I'm doing wrong?
Program.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test {
static class Program {
public static FormMain FormMain = new FormMain();
[STAThread]
static void Main() {
Application.Run(FormMain);
}
}
}
FormMain.cs file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test {
public partial class FormMain : Form {
Button BtnClose = new Button();
public void BtnClose_Setup() {
BtnClose.Text = "Ok";
BtnClose.Top = 500;
BtnClose.Left = 700;
}
public void FormMain_Setup() {
Top = 20;
Left = 20;
Width = 800;
Height = 600;
KeyDown += FormMain_KeyDown;
//Container.Add(BtnClose);
//BtnClose_Setup();
}
void FormMain_KeyDown(object sender, KeyEventArgs e) {
if(e.KeyCode == Keys.Escape) {
Close();
}
}
public FormMain() {
InitializeComponent();
FormMain_Setup();
}
}
}
Call Controls.Add(BtnClose); instead of Container.Add(BtnClose);.
As for fixing the form position: set StartPosition = FormStartPosition.Manual; property.
To properly close the form on Esc, override ProcessCmdKey method:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Escape)
{
Close();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
By default a forms StartPosition is set to WindowsDefaultLocation. You need to set it to Manual; either in the designer or in the code.
To add a control to a form, you want to add it to the form's Controls collection, not the Container.
Also, if you want the form to continue to get KeyDown events after the button is added you need to set KeyPreview to true.
public void FormMain_Setup()
{
StartPosition = FormStartPosition.Manual;
KeyPreview = true;
Top = 20;
Left = 20;
Width = 800;
Height = 600;
KeyDown += FormMain_KeyDown;
Controls.Add(BtnClose);
BtnClose_Setup();
}

Is there a way to detect whether the Winform TextBox's Leave event was triggered by Tab or Shift-Tab or other event?

I will skip my code for now; it should be easier to describe in words.
So far I have the following logic working:
I have an input textbox, and when the user enters bad text, I show an error message and return the focus to the textbox.
When the user enters nothing or deletes what was there and leaves the textbox, it does some processing, but otherwise behaves as it would - jumps to the next control in Tab order.
If I Tab off, jumps to the previous control if I press Shift-Tab or focuses on whatever I click with the mouse.
If I enter a unique prefix for some text that can be auto-completed, such as "articho" that can be auto-completed to "artichoke", the code then auto-fills in another read-only textbox next to it and skips over to the next neighbor of the read-only textbox. Note: If I Shift-Tab with the same input, then it does the same, but I would want to perform different logic in this case.
Just like 4. but if I leave by clicking with the mouse, then the code does auto-fill in the textbox - great, but then it also selects the control that I want.
What is broken right now is the bald part of 4.; if I try to Shift-Tab to cycle all of the interactive (as opposed to labels or disabled ones) controls backwards, I cannot - my custom logic per 4. kicks in and sends the focus forward. This is only a problem when I have some stuff filled in in the textbox at hand, but I still would like to fix this edge case.
Any thoughts? Questions?
P.S. I do not know how to answer the "what have you tried?" type of question other than say that I was using WinForms for several months and I am not sure how to proceed here. Thanks.
Probably you might want to try PreviewKeyDown event of the textbox where you can identify Key combination that was being pressed and execute your different logic if it is Shift + Tab key press.
Here's how I'd do it.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace LeaveTest {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
textBox2.LostFocus += new EventHandler(textBox2_LostFocus);
}
void textBox2_LostFocus(object sender, EventArgs e) {
Control newControl = GetCurrentControl();
Control prevControl = GetPrevControl(textBox2);
Control nextControl = GetNextControl(textBox2);
if (newControl.Handle == prevControl.Handle) {
MessageBox.Show("Case 4");
}
}
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
[DllImport("user32.dll")]
static extern IntPtr GetNextDlgTabItem(IntPtr hDlg, IntPtr hCtl,
bool bPrevious);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
enum GetWindow_Cmd : uint {
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
private Control GetCurrentControl() {
IntPtr hWnd = GetFocus();
Control control = Control.FromHandle(hWnd);
return control;
}
private Control GetNextControl(Control ctrl) {
// I know the last parameter looks wierd, but it works
IntPtr hWnd = GetNextDlgTabItem(ctrl.Parent.Handle, ctrl.Handle, true);
Control control = Control.FromHandle(hWnd);
return control;
}
private Control GetPrevControl(Control ctrl) {
// I know the last parameter looks wierd, but it works
IntPtr hWnd = GetNextDlgTabItem(ctrl.Parent.Handle, ctrl.Handle, false);
Control control = Control.FromHandle(hWnd);
return control;
}
}
}

how to hide on EditText soft keyboard windows 8 Metro Application?

I'm having an EditText and a Button in my Frame using C#. After writing inside the edit field and clicking on the Button, I want to hide the virtual soft keyboard.
Add a dummy button and set focus to it and the keyboard will be hidden.
Thanks for your question.
i have get a better solution for this problem. like this
first we can add handler in xaml
<Grid x:Name= Tapped="Grid_Tapped_1">
......
</Grid >
then we focus current page like follow. it works well.
private void Grid_Tapped_1(object sender, TappedRoutedEventArgs e)
{
this.Focus(FocusState.Programmatic);
}
You cannot. There is more information on the behavior of the Input Hosting Manager and Soft Keyboard and you can register to know when it shows or becomes hidden. But, you cannot programmatically control whether it's up or down.
When the textbox that showed the virtual keyboard has it’s propery IsEnabled set to false, the virtual keyboard disappears. We can immediately set is to true after that and the virtual keyboard will remain hidden. Just like this:
MyTextBox.KeyDown += (s, a) => {
if (a.Key == VirtualKey.Enter) {
MyTextBox.IsEnabled = false;
MyTextBox.IsEnabled = true;
}
};
Try to set the IsReadOnly property of the Textbox`.
I'm doing something "similar"
private void textbox_input_LostFocus(object sender, RoutedEventArgs e)
{
textbox_input.IsReadOnly = false;
}
private void textbox_input_Tapped(object sender, TappedRoutedEventArgs e)
{
if(e.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse)
textbox_input.IsReadOnly = true;
else
textbox_input.IsReadOnly = false;
}
With this snipped I suppress the keyboard if the user isn't using the mouse...
Also the KeyDown event is fired while the textbox is readonly so you could use the data directly to set your viewmodel and update over it your textbox ;)
There is a solution which can hide the touch-keyboard by setting the container's IsTabStop=true automaticly after clicking your Button as "submit".
But, btw, I've noticed that the next time entering that page, the EditText (supposed to be a TextBox) will be auto-focused, and have the touch-keyboard showed. Maybe you'd better Disable the EditText after submitting. (seems to finish and block the input operation)
I had the same problem, only with a little difference.
When I switched from a textbox to a datepicker the softkeyboard won't disappear.
I tried all of your suggestions, but nothing worked like it should. Every time my datepicker had a strange behaviour, after I tried one of the above solutions (Or some of other stackoverflow threads).
After some time I found something via Google, which worked like a charm. HERE
In the comment section Dusher16 wrote a very clean solution, which works also for WinRT / Win8 / Win8.1 / Metro or how you will call it.
Create a new class:
using System.Runtime.InteropServices;
using Windows.Devices.Input;
namespace Your.Namespace
{
public static class TouchKeyboardHelper
{
#region < Attributes >
private const int WmSyscommand = 0x0112; // Flag to received/send messages to the system.
private const int ScClose = 0xF060; // Param to indicate we want to close a system window.
#endregion < Attributes >
#region < Properties >
public static bool KeyboardAttached
{
get { return IsKeyboardAttached(); }
}
#endregion < Properties >
#region < Methods >
[DllImport("user32.dll")]
private static extern int FindWindow(string lpClassName, string lpWindowName); // To obtain an active system window handler.
[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam); // To send a message to the system.
/// <summary>
/// To detect if a real keyboard is attached to the dispositive.
/// </summary>
/// <returns></returns>
private static bool IsKeyboardAttached()
{
KeyboardCapabilities keyboardCapabilities = new KeyboardCapabilities(); // To obtain the properties for the real keyboard attached.
return keyboardCapabilities.KeyboardPresent != 0 ? true : false;
}
/// <summary>
/// To close the soft keyboard
/// </summary>
public static void CloseOnscreenKeyboard()
{
// Retrieve the handler of the window
int iHandle = FindWindow("IPTIP_Main_Window", ""); // To find the soft keyboard window.
if (iHandle > 0)
{
SendMessage(iHandle, WmSyscommand, ScClose, 0); // Send a close message to the soft keyboard window.
}
}
#endregion < Methods >
}
}
And in for example some XAML.cs file you add the following lines:
private void DatePicker_GotFocus(object sender, RoutedEventArgs e)
{
if (TouchKeyboardHelper.KeyboardAttached)
TouchKeyboardHelper.CloseOnscreenKeyboard();
}

Bring a window to the front in WPF

How can I bring my WPF application to the front of the desktop? So far I've tried:
SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);
SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);
None of which are doing the job (Marshal.GetLastWin32Error() is saying these operations completed successfully, and the P/Invoke attributes for each definition do have SetLastError=true).
If I create a new blank WPF application, and call SwitchToThisWindow with a timer, it works exactly as expected, so I'm not sure why it's not working in my original case.
Edit: I'm doing this in conjunction with a global hotkey.
myWindow.Activate();
Attempts to bring the window to the foreground and activates it.
That should do the trick, unless I misunderstood and you want Always on Top behavior. In that case you want:
myWindow.TopMost = true;
I have found a solution that brings the window to the top, but it behaves as a normal window:
if (!Window.IsVisible)
{
Window.Show();
}
if (Window.WindowState == WindowState.Minimized)
{
Window.WindowState = WindowState.Normal;
}
Window.Activate();
Window.Topmost = true; // important
Window.Topmost = false; // important
Window.Focus(); // important
In case you need the window to be in front the first time it loads then you should use the following:
private void Window_ContentRendered(object sender, EventArgs e)
{
this.Topmost = false;
}
private void Window_Initialized(object sender, EventArgs e)
{
this.Topmost = true;
}
Or by overriding the methods:
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Topmost = false;
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
Topmost = true;
}
I know this question is rather old, but I've just come across this precise scenario and wanted to share the solution I've implemented.
As mentioned in comments on this page, several of the solutions proposed do not work on XP, which I need to support in my scenario. While I agree with the sentiment by #Matthew Xavier that generally this is a bad UX practice, there are times where it's entirely a plausable UX.
The solution to bringing a WPF window to the top was actually provided to me by the same code I'm using to provide the global hotkey. A blog article by Joseph Cooney contains a link to his code samples that contains the original code.
I've cleaned up and modified the code a little, and implemented it as an extension method to System.Windows.Window. I've tested this on XP 32 bit and Win7 64 bit, both of which work correctly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace System.Windows
{
public static class SystemWindows
{
#region Constants
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_SHOWWINDOW = 0x0040;
#endregion
/// <summary>
/// Activate a window from anywhere by attaching to the foreground window
/// </summary>
public static void GlobalActivate(this Window w)
{
//Get the process ID for this window's thread
var interopHelper = new WindowInteropHelper(w);
var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);
//Get the process ID for the foreground window's thread
var currentForegroundWindow = GetForegroundWindow();
var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);
//Attach this window's thread to the current window's thread
AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);
//Set the window position
SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
//Detach this window's thread from the current window's thread
AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);
//Show and activate the window
if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
w.Show();
w.Activate();
}
#region Imports
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
#endregion
}
}
I hope this code helps others who encounter this problem.
To make this a quick copy-paste one -
Use this class' DoOnProcess method to move process' main window to foreground (but not to steal focus from other windows)
public class MoveToForeground
{
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int SWP_SHOWWINDOW = 0x0040;
const int SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
public static void DoOnProcess(string processName)
{
var allProcs = Process.GetProcessesByName(processName);
if (allProcs.Length > 0)
{
Process proc = allProcs[0];
int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
// Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
}
}
}
HTH
Why some of the answers on this page are wrong!
Any answer that uses window.Focus() is wrong.
Why? If a notification message pops up, window.Focus() will grab the focus away from whatever the user is typing at the time. This is insanely frustrating for end users, especially if the popups occur quite frequently.
Any answer that uses window.Activate() is wrong.
Why? It will make any parent windows visible as well.
Any answer that omits window.ShowActivated = false is wrong.
Why? It will grab the focus away from another window when the message pops up which is very annoying!
Any answer that does not use Visibility.Visible to hide/show the window is wrong.
Why? If we are using Citrix, if the window is not collapsed when it is closed, it will leave a weird black rectangular hold on the screen. Thus, we cannot use window.Show() and window.Hide().
Essentially:
The window should not grab the focus away from any other window when it activates;
The window should not activate its parent when it is shown;
The window should be compatible with Citrix.
MVVM Solution
This code is 100% compatible with Citrix (no blank areas of the screen). It is tested with both normal WPF and DevExpress.
This answer is intended for any use case where we want a small notification window that is always in front of other windows (if the user selects this in the preferences).
If this answer seems more complex than the others, it's because it is robust, enterprise level code. Some of the other answers on this page are simple, but do not actually work.
XAML - Attached Property
Add this attached property to any UserControl within the window. The attached property will:
Wait until the Loaded event is fired (otherwise it cannot look up the visual tree to find the parent window).
Add an event handler that ensures that the window is visible or not.
At any point, you can set the window to be in front or not, by flipping the value of the attached property.
<UserControl x:Class="..."
...
attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
"{Binding EnsureWindowInForeground, Mode=OneWay}">
C# - Helper Method
public static class HideAndShowWindowHelper
{
/// <summary>
/// Intent: Ensure that small notification window is on top of other windows.
/// </summary>
/// <param name="window"></param>
public static void ShiftWindowIntoForeground(Window window)
{
try
{
// Prevent the window from grabbing focus away from other windows the first time is created.
window.ShowActivated = false;
// Do not use .Show() and .Hide() - not compatible with Citrix!
if (window.Visibility != Visibility.Visible)
{
window.Visibility = Visibility.Visible;
}
// We can't allow the window to be maximized, as there is no de-maximize button!
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
window.Topmost = true;
}
catch (Exception)
{
// Gulp. Avoids "Cannot set visibility while window is closing".
}
}
/// <summary>
/// Intent: Ensure that small notification window can be hidden by other windows.
/// </summary>
/// <param name="window"></param>
public static void ShiftWindowIntoBackground(Window window)
{
try
{
// Prevent the window from grabbing focus away from other windows the first time is created.
window.ShowActivated = false;
// Do not use .Show() and .Hide() - not compatible with Citrix!
if (window.Visibility != Visibility.Collapsed)
{
window.Visibility = Visibility.Collapsed;
}
// We can't allow the window to be maximized, as there is no de-maximize button!
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
window.Topmost = false;
}
catch (Exception)
{
// Gulp. Avoids "Cannot set visibility while window is closing".
}
}
}
Usage
In order to use this, you need to create the window in your ViewModel:
private ToastView _toastViewWindow;
private void ShowWindow()
{
if (_toastViewWindow == null)
{
_toastViewWindow = new ToastView();
_dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
}
ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}
private void HideWindow()
{
if (_toastViewWindow != null)
{
HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
}
}
Additional links
For tips on how ensure that a notification window always shifts back onto the visible screen, see my answer: In WPF, how to shift a window onto the screen if it is off the screen?.
If the user is interacting with another application, it may not be possible to bring yours to the front. As a general rule, a process can only expect to set the foreground window if that process is already the foreground process. (Microsoft documents the restrictions in the SetForegroundWindow() MSDN entry.) This is because:
The user "owns" the foreground. For example, it would be extremely annoying if another program stole the foreground while the user is typing, at the very least interrupting her workflow, and possibly causing unintended consequences as her keystrokes meant for one application are misinterpreted by the offender until she notices the change.
Imagine that each of two programs checks to see if its window is the foreground and attempts to set it to the foreground if it is not. As soon as the second program is running, the computer is rendered useless as the foreground bounces between the two at every task switch.
I know that this is late answer, maybe helpful for researchers
if (!WindowName.IsVisible)
{
WindowName.Show();
WindowName.Activate();
}
I have had a similar problem with a WPF application that gets invoked from an Access application via the Shell object.
My solution is below - works in XP and Win7 x64 with app compiled to x86 target.
I'd much rather do this than simulate an alt-tab.
void Window_Loaded(object sender, RoutedEventArgs e)
{
// make sure the window is normal or maximised
// this was the core of the problem for me;
// even though the default was "Normal", starting it via shell minimised it
this.WindowState = WindowState.Normal;
// only required for some scenarios
this.Activate();
}
Well, since this is such a hot topic... here is what works for me. I got errors if I didn't do it this way because Activate() will error out on you if you cannot see the window.
Xaml:
<Window ....
Topmost="True"
....
ContentRendered="mainWindow_ContentRendered"> .... </Window>
Codebehind:
private void mainWindow_ContentRendered(object sender, EventArgs e)
{
this.Topmost = false;
this.Activate();
_UsernameTextBox.Focus();
}
This was the only way for me to get the window to show on top. Then activate it so you can type in the box without having to set focus with the mouse. control.Focus() wont work unless the window is Active();
Well I figured out a work around. I'm making the call from a keyboard hook used to implement a hotkey. The call works as expected if I put it into a BackgroundWorker with a pause. It's a kludge, but I have no idea why it wasn't working originally.
void hotkey_execute()
{
IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(delegate
{
Thread.Sleep(10);
SwitchToThisWindow(handle, true);
});
bg.RunWorkerAsync();
}
To show ANY currently opened window import those DLL:
public partial class Form1 : Form
{
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);
[DllImportAttribute("User32.dll")]
private static extern int SetForegroundWindow(int hWnd);
and in program We search for app with specified title (write title without first letter (index > 0))
foreach (Process proc in Process.GetProcesses())
{
tx = proc.MainWindowTitle.ToString();
if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
{
tx = proc.MainWindowTitle;
hWnd = proc.Handle.ToInt32(); break;
}
}
hWnd = FindWindow(null, tx);
if (hWnd > 0)
{
SetForegroundWindow(hWnd);
}
These codes will work fine all times.
At first set the activated event handler in XAML:
Activated="Window_Activated"
Add below line to your Main Window constructor block:
public MainWindow()
{
InitializeComponent();
this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}
And inside the activated event handler copy this codes:
private void Window_Activated(object sender, EventArgs e)
{
if (Application.Current.Windows.Count > 1)
{
foreach (Window win in Application.Current.Windows)
try
{
if (!win.Equals(this))
{
if (!win.IsVisible)
{
win.ShowDialog();
}
if (win.WindowState == WindowState.Minimized)
{
win.WindowState = WindowState.Normal;
}
win.Activate();
win.Topmost = true;
win.Topmost = false;
win.Focus();
}
}
catch { }
}
else
this.Focus();
}
These steps will works fine and will bring to front all other windows into their parents window.
Just wanted to add another solution to this question. This implementation works for my scenario, where CaliBurn is responsible for displaying the main Window.
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IMainWindowViewModel>();
Application.MainWindow.Topmost = true;
Application.MainWindow.Activate();
Application.MainWindow.Activated += OnMainWindowActivated;
}
private static void OnMainWindowActivated(object sender, EventArgs e)
{
var window = sender as Window;
if (window != null)
{
window.Activated -= OnMainWindowActivated;
window.Topmost = false;
window.Focus();
}
}
The problem could be that the thread calling your code from the hook hasn't been initialized by the runtime so calling runtime methods don't work.
Perhaps you could try doing an Invoke to marshal your code on to the UI thread to call your code that brings the window to the foreground.
If you are trying to hide the window, for example you minimize the window, I have found that using
this.Hide();
will hide it correctly, then simply using
this.Show();
will then show the window as the top most item once again.
Remember not to put the code that shows that window inside a PreviewMouseDoubleClick handler as the active window will switch back to the window who handled the event.
Just put it in the MouseDoubleClick event handler or stop bubbling by setting e.Handled to True.
In my case i was handling the PreviewMouseDoubleClick on a Listview and was not setting the e.Handled = true then it raised the MouseDoubleClick event witch sat focus back to the original window.
This is a combination of a few suggestions above that works well and is simple. It only comes to front when those events fire, so any window that pops up after the event will stay on top of course.
public partial class MainWindow : Window
{
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Topmost = true;
Topmost = false;
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
Topmost = true;
Topmost = false;
}
....
}
I wanted to create a launcher with the keyboard hook and had the same problem.
After much trial and error, this solved the problem.
void Active()
{
MainWindow0.Show();
MainWindow0.Focus();
MainWindow0.Activate();
MainWindow0.WindowState = WindowState.Normal;
}
void Deactive()
{
MainWindow0.Hide();
MainWindow0.WindowState = WindowState.Minimized;
}
I built an extension method to make for easy reuse.
using System.Windows.Forms;
namespace YourNamespace{
public static class WindowsFormExtensions {
public static void PutOnTop(this Form form) {
form.Show();
form.Activate();
}// END PutOnTop()
}// END class
}// END namespace
Call in the Form Constructor
namespace YourNamespace{
public partial class FormName : Form {
public FormName(){
this.PutOnTop();
InitalizeComponents();
}// END Constructor
} // END Form
}// END namespace

Categories