microsoft-ui-xaml
                                
                                 microsoft-ui-xaml copied to clipboard
                                
                                    microsoft-ui-xaml copied to clipboard
                            
                            
                            
                        Window.Activate does not activate and bring window to foreground in WinUI3 if window is in background but not minimized
Describe the bug
If Activate is called on a Window which is in the background of other windows, that window is not activated and brought to the foreground. If the window is minimized it works correctly.
Steps to reproduce the bug
Call Activate on a Window when it is in the backround of other windows.
Expected behavior
No response
Screenshots
No response
NuGet package version
WinUI 3 - Windows App SDK 1.1.4
Windows app type
- [ ] UWP
- [X] Win32
Device form factor
Desktop
Windows version
Windows 10 (21H2): Build 19044
Additional context
No response
I ran into this issue when making my WinUI3 app single-instanced. Any idea when the bug could be resolved?
Exactly where the bug hit me too. Had to call SetForegroundWindow. Please fix this.
looking at it
I just tried in the latest version of windows app sdk 1.2 and not able to reproduce  it. I created a bunch of windows, stacked them one behind the other, called .Activate() on one of them and it showed up.
Can you verify that after updating to winappsdk 1.2, it goes away ? Feel free to re-open this bug if it still persists.
This is not fixed in 1.2! Running code like this
// Wire up the activated event handler.
keyInstance.Activated += async (sender, e) =>
{
  // When activated, activate the main window and bring it to the foreground.
  await _mainWindow.DispatcherQueue.EnqueueAsync(() => _mainWindow.Activate());
  //NativeMethods.SetForegroundWindow(_mainWindow.GetWindowHandle());
};
outside the debugger, does not bring the window to the foreground. Only once the native call is uncommented the window is brought to the foreground!
thanks for verifying it. i will try this out quickly.
@Balkoth It looks like you are using Window community toolkit for dispatcher queue. Could you share a sample project which I can compile and build locally to investigate the issue?
Meanwhile, I also have a workaround : if you move away from windows community toolkit and directly use dispatcher queue which is part of windows app sdk 1.2 https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.dispatching.dispatcherqueue?view=windows-app-sdk-1.2
It solves this issue. However, we definitely need to fix community toolkit bug so we need the repro too :)
Is there a sample available for the Windows App SDK dispatcher queue? The link you posted puts a big question mark over my head...
WinUI Gallery source code has some parts which uses this inbuilt dispatcher queue : https://github.com/microsoft/WinUI-Gallery/blob/353c1a0dab0aec9485179ad2a8b76cab95b7c8b9/WinUIGallery/TabViewPages/TabViewWindowingSamplePage.xaml.cs#L179
See if it helps.
I will try it tomorrow and report back.
Using the Windows App SDK dispatcher queue does also not work...
// Wire up the activated event handler.
keyInstance.Activated += async (sender, e) =>
{
  var taskCompletionSource = new TaskCompletionSource();
  _mainWindow.DispatcherQueue.TryEnqueue(
      Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal,
      new Microsoft.UI.Dispatching.DispatcherQueueHandler(() =>
      {
        _mainWindow.Activate();
        taskCompletionSource.SetResult();
      }));
  await taskCompletionSource.Task;
};
Here is the sample project: WindowActivateTest.zip
thanks for confirming. i will try out this test app.
Thanks for sample app. I debugged it. Turns out AppInstance.Activated event is not firing and that's why your window is not coming forward.
If you hook this code to any other event's firing like button clicked, it starts working. So Window activation is working as expected.
 .
.
So, you can debug AppInstance code to see why it is not working. Closing the issue as it is a no repro.
WTF are you talking about. Of course the event is called, if you put in the native call to SetForegroundWindow the window is activated an put to the foreground. Clearly you don't seem to be qualified to analyze this issue, please bring a colleage with more experience.
So just for the record:
- AppInstance.Activatedis f.e. fired when you try to start a second instance of the app and you have registered it with- AppInstance.FindOrRegisterForKey
- The sample you posted is severely flawed, because you call myWindow.Activatewhen the window is already activated. Your second call on the dispatcher queue will only ever activate the window and bring it to the foreground, if the window is minimized. If the window just sits in the background of other windows it will not be brought to the foreground.
The docs Window.Activate clearly state: Attempts to activate the application window by bringing it to the foreground and setting the input focus to it.
P.S.: Posting screenshots of code creates a bad experience for anyone trying to recreate what you did. This platform supports code tags which nicely format the text.
So will this be reopened and investigated properly or do i have to create a new issue?
My apologies. I was not launching the second instance. Now I am able to get the repro done. We are investigating this and I will keep the issue open until you validate the fix.
Still investigating?
Question: Why/when use this methiod over Show() ?
This worked for me (I needed my app to be single instanced too and if user tried to run app again, already running instance's window get activated)
This worked for me
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public enum ShowWindowCommands : int
{
	Hide = 0,
	ShowNormal = 1,
	ShowMinimized = 2,
	ShowMaximized = 3,
	Maximize = 3,
	ShowNormalNoActivate = 4,
	Show = 5,
	Minimize = 6,
	ShowMinNoActivate = 7,
	ShowNoActivate = 8,
	Restore = 9,
	ShowDefault = 10,
	ForceMinimized = 11
}
in app.Xaml.cs
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
	// Get the activation args
	var appArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
	
	// Get or register the main instance
	var mainInstance = AppInstance.FindOrRegisterForKey("My.App");
	// If the main instance isn't this current instance
	
	if (!mainInstance.IsCurrent)
		{
			var activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
			await mainInstance.RedirectActivationToAsync(activatedEventArgs);
			Process.GetCurrentProcess().Kill();
			return;
		}
	// Otherwise, register for activation redirection
	AppInstance.GetCurrent().Activated += AppActivated;
}
private void AppActivated(object sender, AppActivationArguments e)
{
	IntPtr hWnd = WindowNative.GetWindowHandle(_mainWindow);
	//this line causing a delay in reactivating main window, it needed to restore window if it was minimized
	ShowWindow(hWnd, (int)NativeMethods.ShowWindowCommands.ShowNormal);
	//this method will bring main window to front
	SetForegroundWindow(hWnd);
}        
This is still an issue in Windows App SDK 1.3.2 (1.3.230602002)
Seems to still be a problem in WASDK 1.4, is there any ETA for this?
Does the explorer team using WinUi3 also just work around bugs like this? I would get really mad if i was on that team and long-standing bugs like this are still open.
IntPtr hWnd = WindowNative.GetWindowHandle(_mainWindow); //this line causing a delay in reactivating main window, it needed to restore window if it was minimized ShowWindow(hWnd, (int)NativeMethods.ShowWindowCommands.ShowNormal); //this method will bring main window to front SetForegroundWindow(hWnd);
Worked like a champ, thank you.
I was hitting the same issue today as well. My goal is to activate/foreground the apps single-instanced window after the user clicks a toast notification of the same app (a pretty common scenario I would say). The SetForegroundWindow workaround posted above does not work if the debugger isn't attached due to the reasons here.
A similar behavior can be observed when using Windows.System.Launcher.LaunchUriAsync. Normally this would launch and foreground your web browser if you call it, e.g. after clicking a button in the main window. However if you call it in Program.Main it launches your browser, but doesn't foreground it.
I was hitting the same issue today as well. My goal is to activate/foreground the apps single-instanced window after the user clicks a toast notification of the same app (a pretty common scenario I would say). The
SetForegroundWindowworkaround posted above does not work if the debugger isn't attached due to the reasons here.
An API which generally works is SwitchToThisWindow (they say "It may be altered...", but it is used by Task Manager for ages...) (I used it for example in this test sample to set the main window to foreground with a Hotkey : MainWindow.xaml.cs)
@castorix sadly, this also doesn't work for me...
@castorix sadly, this also doesn't work for me...
I converted an old C++ function into C#, mixing all APIs. If it does not work for you, I have no more idea...
    private void SwitchToWindow(IntPtr hWnd)
    {
        int nLockTimeOut = 0;
        IntPtr hCurrWnd = GetForegroundWindow();
        int nPID = 0;
        uint nThisTID = GetCurrentThreadId(), nCurrTID = GetWindowThreadProcessId(hCurrWnd, out nPID);
        if (nThisTID != nCurrTID)
        {
            AttachThreadInput(nThisTID, nCurrTID, true);
            SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref nLockTimeOut, 0);
            int nNewLockTimeOut = 0;
            SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref nNewLockTimeOut, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
            AllowSetForegroundWindow(-1);
        }
        if (IsIconic(hWnd))
            ShowWindow(hWnd, SW_RESTORE);
        IntPtr hWndLastActivePopup = GetLastActivePopup(hWnd);
        SwitchToThisWindow(hWndLastActivePopup, true);           
        SetForegroundWindow(hWnd);
        if (nThisTID != nCurrTID)
        {
            SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref nLockTimeOut, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
            AttachThreadInput(nThisTID, nCurrTID, false);
        }
    }
with :
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    //public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
    public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, [In, Out] ref int pvParam, uint fWinIni);
    public const int SPIF_UPDATEINIFILE = 0x0001;
    public const int SPIF_SENDWININICHANGE = 0x0002;
    public const int SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
    public const int SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern IntPtr GetForegroundWindow();
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern uint GetCurrentThreadId();
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool AllowSetForegroundWindow(int dwProcessId);
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    public const int SW_HIDE = 0;
    public const int SW_SHOWNORMAL = 1;
    public const int SW_SHOWMINIMIZED = 2;
    public const int SW_SHOWMAXIMIZED = 3;
    public const int SW_RESTORE = 9;
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool IsIconic(IntPtr hWnd);
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool SetForegroundWindow(IntPtr hWnd);
I did this as a temporary solution.
In App.xaml.cs
protected async override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
	var mainInstance = Microsoft.Windows.AppLifecycle.AppInstance.FindOrRegisterForKey("main");
	var activatedEventArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
	if (!mainInstance.IsCurrent)
	{
   
		await mainInstance.RedirectActivationToAsync(activatedEventArgs);
		System.Diagnostics.Process.GetCurrentProcess().Kill();
		return;
	}
	m_window = new MainWindow();
	m_window.Activate();
	mainInstance.Activated += MainInstance_Activated;
}
private void MainInstance_Activated(object sender, Microsoft.Windows.AppLifecycle.AppActivationArguments e)
{
	General.WinPresenter.Minimize();
	General.WinPresenter.Restore();
}
In MainWindow:
public MainWindow()
{
    this.InitializeComponent();
    General.WndHnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
}
private void WinLoaded()
{
	AppWindow CurWin;
	WindowId WinID = Win32Interop.GetWindowIdFromWindow(General.WndHnd);
	CurWin = AppWindow.GetFromWindowId(WinID);
	General.WinPresenter = CurWin.Presenter as OverlappedPresenter;
}
common class in the project
internal class General
{
	public static IntPtr WndHnd;
	public static Microsoft.UI.Windowing.OverlappedPresenter WinPresenter;
}
hi Team, is there any update on this issue? Thanks.