带ProgressBar的WPF飞溅屏幕

带ProgressBar的WPF飞溅屏幕,wpf,splash-screen,Wpf,Splash Screen,我有一个WPF项目,项目向导添加了一个启动屏幕。在同一个启动屏幕上,我想添加一个进度条样式的仪表。有人知道怎么做吗?这是我的方案。我这样做的动机是,我不想让初始化代码在UI线程上运行,通常我希望初始化代码在我的应用程序类(而不是启动屏幕)上运行 基本上,我将应用程序StartupUri设置为我的启动屏幕,这样就可以启动了 在启动屏幕上,我调用应用程序上的委托。这是在工作线程上运行的。在启动屏幕中,我处理EndInvoke,然后关闭窗口 在应用程序初始化委托中,我完成了这项工作,最后创建并打开了正

我有一个WPF项目,项目向导添加了一个启动屏幕。在同一个启动屏幕上,我想添加一个进度条样式的仪表。有人知道怎么做吗?

这是我的方案。我这样做的动机是,我不想让初始化代码在UI线程上运行,通常我希望初始化代码在我的应用程序类(而不是启动屏幕)上运行

基本上,我将应用程序
StartupUri
设置为我的启动屏幕,这样就可以启动了

在启动屏幕上,我调用应用程序上的委托。这是在工作线程上运行的。在启动屏幕中,我处理
EndInvoke
,然后关闭窗口

在应用程序初始化委托中,我完成了这项工作,最后创建并打开了正常的主窗口。在工作负载期间,我还有一个斜杠方法,允许我更新进度

好的,代码相当短,不包括主窗口代码(不受所有这些影响),但它会隐藏匿名委托,因此请仔细阅读,最好在调试器中使用它

这是代码

<Application x:Class="SplashScreenDemo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Splash.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>
splash
xaml
(实际上,这里没有什么太有趣的…)


由于工作是在工作线程上完成的,进度条将很好地更新,并且您在初始屏幕上的任何动画都将使娱乐继续进行。

我使用了.NET Core,当有一个新线程
Application.OnExit()
启动时。因此,我实现这一目标的唯一方法是:

Application.cs:

启动时受保护的覆盖无效(StartupEventArgs e)
{
基础。启动时(e);
_mySplashScreenWindow.Show();
Task.Run(异步()=>
{
对于(var i=1;i
{
_mySplashScreenWindow.SomeTextBlock.Text=i.ToString();
_mySplashScreenWindow.Progress=i;//或i/20表示%
});
等待任务。延迟(250);
}
})
.ContinueWith(=>
{
主窗口=空;
var mainWindow=新的mainWindow();
//或者,如果您可以访问主窗口中的SplashScreen,您可以在那里订阅
mainWindow.Loaded+=(发送方,参数)=>
{
_mySplashScreenWindow.Close();
_mySplashScreenWindow=null;
}
主窗口=主窗口;
mainWindow.ShowDialog();
},TaskScheduler.FromCurrentSynchronizationContext());
}

阿里的答案在.NET core上不起作用。然而,有一个变通办法,在我看来,它更直接。我相信它适用于所有“最新”版本的.NET(可能是添加了Task.Run之后)

我使用了类似的方法,使用另一个窗口作为启动屏幕

My App.xaml使用启动事件而不是StartupUri。不过,我相信这没什么区别

<Application x:Class="SplashScreenDemo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Startup="OnStartup">
    <Application.Resources>
    </Application.Resources>
</Application>
启动屏幕窗口可以使用一些窗口属性:

  • WindowsStartupLocation=“CenterScreen”不言自明
  • WindowStyle=“None”以避免出现标题栏
  • ResizeMode=“NoResize”以防止用户移动或调整其大小
  • Topmost=“True”使其始终显示在其他窗口的顶部

所以您初始化的所有内容都存储在全局变量中?(Invoker)对我来说不起作用,但将其替换为“newaction(delegate()”didA以下划线开头的方法声明…真的吗?
<Window x:Class="SplashScreenDemo.Splash"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Splash" Height="300" Width="300">
    <Grid>
        <TextBlock Height="21" Margin="91,61,108,0" VerticalAlignment="Top">Splash Screen</TextBlock>
        <ProgressBar Name="progBar" Margin="22,122,16,109" Minimum="0" Maximum="1"/>
    </Grid>
</Window>
public partial class Splash : Window
{
    public Splash()
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(Splash_Loaded);
    }

    void Splash_Loaded(object sender, RoutedEventArgs e)
    {
        IAsyncResult result = null;

        // This is an anonymous delegate that will be called when the initialization has COMPLETED
        AsyncCallback initCompleted = delegate(IAsyncResult ar)
        {
            App.Current.ApplicationInitialize.EndInvoke(result);

            // Ensure we call close on the UI Thread.
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Invoker)delegate { Close(); });
        };

        // This starts the initialization process on the Application
        result = App.Current.ApplicationInitialize.BeginInvoke(this, initCompleted, null);
    }

    public void SetProgress(double progress)
    {
        // Ensure we update on the UI Thread.
        Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Invoker)delegate { progBar.Value = progress; });           
    }
}
<Application x:Class="SplashScreenDemo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Startup="OnStartup">
    <Application.Resources>
    </Application.Resources>
</Application>
public partial class App : Application
{
    public App()
    {
    }
    
    public static new App Current { get => Application.Current as App; }

    private void OnStartup(object sender, StartupEventArgs e)
    {
        var splashScreen = new SplashScreenDemo.Splash();
        splashScreen.Show();
    }

    internal void InitializeApplication(Splash splashWindow)
    {
        // fake workload, but with progress updates.
        Thread.Sleep(500);
        splashWindow.SetProgress(0.25);

        Thread.Sleep(500);
        splashWindow.SetProgress(0.5);

        Thread.Sleep(500);
        splashWindow.SetProgress(0.75);

        EventWaitHandle mainWindowLoaded = new ManualResetEvent(false);

        // Create the main window, but on the UI thread.
        Dispatcher.BeginInvoke((Action)(() =>
        {
            MainWindow = new Window1();
            MainWindow.Loaded += (sender, e) =>
            {
                mainWindowLoaded.Set();
            };
            splashWindow.SetProgress(0.9);
            MainWindow.Show();
            splashWindow.SetProgress(1);
        }));
        
        // Wait until the Main window has finished initializing and loading
        mainWindowLoaded.WaitOne();        
    }
}
<Window x:Class="SplashScreenDemo.Splash"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Splash" Height="300" Width="300" WindowStartupLocation="CenterScreen"
    WindowStyle="None" ResizeMode="NoResize" Topmost="True">
    <Grid>
        <TextBlock Height="21" VerticalAlignment="Top" TextAlignment="Center" Text="Loading"/>
        <ProgressBar Name="progBar" Margin="20,100" Minimum="0" Maximum="1"/>
    </Grid>
</Window>
public partial class Splash : Window
{
    public Splash()
    {
        InitializeComponent();
        this.Loaded += Splash_Loaded;
    }

    private async void Splash_Loaded(object sender, RoutedEventArgs e)
    {
        await Task.Run(() =>
        {
            App.Current.InitializeApplication(this);
            App.Current.Dispatcher.BeginInvoke((Action)(() =>
            {
                Close();
            }));
        });
    }

    public void SetProgress(double progress)
    {
        Dispatcher.BeginInvoke((Action)(() => progBar.Value = progress));           
    }
}