关闭闪屏后,WPF 显示在当前聚焦的窗口后面

问题描述 投票:0回答:1

我们有一个 WPF 应用程序,它在启动期间显示闪屏

    _splashViewModel = new SplashViewModel(versionTrimmed);
    var t = new Thread(() =>
    {
        var splash = ShowSplashScreen(_splashViewModel);
        splash.ShowDialog();
    });
    t.SetApartmentState(ApartmentState.STA);
    t.Start();

创建实际应用程序并加载其所有配置后,我们关闭启动屏幕,并显示主窗口。


    public void StartSystemControl(
        ICardMasterOneViewModel mainViewModel, 
        SplashViewModel splashViewModel,
        Thread thread)
    {
        var mainWindow = new CMOMainWindow { DataContext = mainViewModel };
        System.Windows.Application.Current.MainWindow = mainWindow;
        splashViewModel.DialogResult = true;
    
        thread.Join();
        mainWindow.Show();
        mainWindow.Activate();
    }

主应用程序将始终出现在当前聚焦的窗口后面,这很烦人。

尝试1:

通过在

mainWindow.TopMost = true
 之前设置 
mainWindow.Show()

来修复它
    mainWindow.Topmost = true;
    mainWindow.Show();
    mainWindow.Topmost = false;

这解决了问题,但现在 WPF 应用程序始终位于顶部,即使在显示窗口后设置

mainWindow.Topmost = false;
后也是如此。这对我们来说是不可接受的。

尝试2:

显示后激活窗口

    mainWindow.Show();
    mainWindow.Activate();

这不会改变行为。我还没有检查过,但我也希望

Show
无论如何都会隐式激活窗口。但无论如何,这并不能解决问题。

当我将启动屏幕全部注释掉时,主应用程序将按预期在前台正确显示。我仍然无法通过消息泵完全拼凑出窗口深处发生的事情。

有人有这种显示启动画面的经验,并且有解决这个特定问题的方法吗?

对于有兴趣重现此内容的人

闪屏视图模型

    public class SplashViewModel : ViewModelBase
    {
        private bool? dialogResult;
        private string machineFamily;

        public string MachineFamily
        {
            get => machineFamily;
            set { Set(() => MachineFamily, ref machineFamily, value); }
        }

        public string VersionInfo { get; }

        public bool? DialogResult
        {
            get => dialogResult;
            set { Set(() => DialogResult, ref dialogResult, value); }
        }

        public SplashViewModel(string versionInfo)
        {
            VersionInfo = versionInfo;
        }
    }

WPF 窗口

<Window x:Class="IAI.UserInterface.Views.Core.SplashScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:behaviors="clr-namespace:IAI.UserInterface.Views.Core.Behaviors"
        xmlns:splash="clr-namespace:IAI.UserInterface.ViewModels.Core"
        mc:Ignorable="d"
        Title="SplashScreen"
        Height="480" Width="640"
        WindowStyle="None"
        Topmost="True"
        ShowInTaskbar="False"
        ResizeMode="NoResize"
        MouseDown="SplashScreen_OnMouseDown"
        behaviors:DialogCloseBehavior.DialogResult="{Binding DialogResult}"
        AllowsTransparency="True"
        d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type=splash:SplashViewModel}">

    <Window.Background>
        <ImageBrush ImageSource="../Resources/SplashBackground.png"/>
    </Window.Background>

    <Border BorderThickness="1" BorderBrush="Gray">
        <StackPanel VerticalAlignment="Center">
            <TextBlock FontFamily="Verdana"
                       FontSize="48"
                       HorizontalAlignment="Center"
                       TextAlignment="Center"
                       Opacity="0.7"
                       Text="{Binding MachineFamily}" Margin="0,0,0,16">
            </TextBlock>

            <TextBlock FontFamily="Verdana"
                       FontWeight="Light"
                       FontSize="16"
                       HorizontalAlignment="Center"
                       TextAlignment="Center"
                       Opacity="0.7"
                       Text="{Binding VersionInfo, StringFormat=Version: {0}}">
            </TextBlock>
        </StackPanel>
    </Border>
</Window>

OnStartup
实现(已清理,仅显示此问题的相关部分)

    private void App_OnStartup(object sender, StartupEventArgs e)
    {
        // DispatcherHelper should be initialized from the UI thread for which the Static Main is appropriate
        DispatcherHelper.Initialize();
        Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));

        var application = Current;
        string machineNumber = "some identifier";
        try
        {
            var version = "some version";

            var splashViewModel = new SplashViewModel(versionTrimmed);
            var t = new Thread(() =>
            {
                var splash = ShowSplashScreen(splashViewModel);
                splash.ShowDialog();
            });
            t.SetApartmentState(ApartmentState.STA);
            t.Start();

            // Removed actual startup behavior (loading config etc)...

            var mainWindow = new MainWindow { DataContext = new MainViewModel() };
            System.Windows.Application.Current.MainWindow = mainWindow;
            splashViewModel.DialogResult = true;

            mainWindow.Show();
        }
        catch (Exception ex)
        {
             // removed for simplicity
        }
    }

c# wpf splash-screen
1个回答
0
投票

啊哈,我终于发现问题了...

它与闪屏完全无关。问题是 MainWindow 在 OnWindowLoaded 事件中显示登录窗口。登录窗口是模态的,因此可以有效地阻止

mainWindow.Show

我们通过将“显示登录窗口”推回事件队列来解决这个问题。这样窗口就可以显示对话框,将其设置为活动状态,然后模式对话框将立即显示。

    // Next line was blocked by OnLoad event which showed the modal dialog for login window
    mainWindow.Show();
    // Next line would not execute until user manually pulled the main window to front, and logged in (which no longer was necessary then, because the user already solved the problem manually of course)
    mainWindow.Activate();

我们现在触发登录窗口,显示如下:


    void ShowLoginWindow() => _loginViewModel.ShowWindow();
    // Enforce that the login window is pushed on the event queue so that the windows load event 
    // is not blocked by whatever happens in the login window
    // After loading the main window, it must be activated so that windows can show it as foreground app
    DispatcherHelper.UIDispatcher.BeginInvoke((Action)ShowLoginWindow);

© www.soinside.com 2019 - 2024. All rights reserved.