我创建了一个小型 .NET 6 WPF 应用程序来展示这个问题。
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var notifier = new Notifier();
//Send Toast
notifier.SendToast();
//Close MainWindow
Close();
}
}
我正在使用 Microsoft.Toolkit.Uwp.Notifications NuGet 包来使用 ToastContentBuilder 发送 Toast 通知。
public class Notifier
{
public Notifier()
{
SubscribeToToastCallback();
}
public void SendToast()
{
var toastContentBuilder = new ToastContentBuilder();
toastContentBuilder.AddText("Text").AddButton("Test", ToastActivationType.Foreground, "");
toastContentBuilder.Show();
}
private void SubscribeToToastCallback()
{
ToastNotificationManagerCompat.OnActivated += toastArgs =>
{
//On Toast button click, Show MainWindow activated
Application.Current.Dispatcher.BeginInvoke(() =>
{
if (Application.Current.MainWindow is null)
{
Application.Current.MainWindow = new MainWindow();
Application.Current.MainWindow.ShowActivated = true;
}
Application.Current.MainWindow.Show();
});
};
}
}
我期望发生的事情: Toast 按钮被点击 -> ToastNotificationManagerCompat.OnActivated 被触发 -> 我打开 MainWindow 的代码被执行 -> MainWindow 在前台打开。
实际上发生了什么: Toast 按钮被点击 -> ToastNotificationManagerCompat.OnActivated 被触发 -> 我打开 MainWindow 的代码被执行 -> MainWindow 在前台打开 -> ~0.5 秒后 MainWindow 失去焦点,之前打开的应用程序被激活。
还有一个有趣的例外:
您可以连续重现此场景 10 次,但是如果您单击 toast Body(可交互),它将正确激活我的窗口。此外,它还会使后续通知正确激活窗口,即使您单击了以前尝试导致焦点丢失的按钮。
此外,当 MainWindow 在这种情况下失去焦点时,不会触发 MainWindow.Deactivated 事件(基于 WA_INACTIVE 消息)。所以应用程序不知道 MainWindow 失去了焦点。
我尝试将 ToastActivationType.Foreground 更改为 Background,但没有任何改变。
Show/Focus/Activate() 的所有组合都无济于事。
使用 PInvoke 尝试设置 LockSetForegroundWindow(),没有任何改变。
唯一有效但非常笨拙的是: MainWindow 打开 -> 设置 Topmost = true -> 保持 1 秒(同时 Windows 试图窃取焦点) -> 设置 Topmost = false。
MainWindow.Topmost = true;
Task.Delay(1000).ContinueWith((_) => { Dispatcher.Invoke(() => { MainWindow.Topmost = false; }); });
有谁知道为什么会发生这种情况?它在 0.5 秒后窃取焦点是 Windows 错误吗?还有比我使用 Topmost 找到的解决方案更简单的解决方案吗?
谢谢!
环境:Windows 10 x64 Build 19045