【问题标题】:Splash Screen Not Closing Based Off Progress Bar闪屏不关闭基于进度条
【发布时间】:2014-01-02 20:51:19
【问题描述】:

Form1.cs

public Form1()
    {
        Thread SplashThread = new Thread(new ThreadStart(SplashScreen));
        SplashThread.Start();
        Thread.Sleep(5000);

        SplashThread.Abort();

        InitializeComponent();

        this.BringToFront();

        PlayerOne[1] = new BladeWarrior();
        PlayerOne[2] = new FistWarrior();
        PlayerOne[3] = new Archer();
        PlayerOne[4] = new RedMage();
        PlayerOne[5] = new BlueMage();

    }
    public void SplashScreen()
    {
        Application.Run(new SplashScreen());
    }

SplashScreen.cs

public SplashScreen()
        {
            InitializeComponent();

            LoadGearFiles LoadGear = new LoadGearFiles();

            LoadGear.StartPatching(this);

        }
        Timer t = new Timer();


        void t_Tick(object sender, EventArgs e)
        {


            if (LoadingBar.Value == 100) t.Stop();

        }

加载齿轮文件.cs

public void StartPatching(SplashScreen Splash)
        {
            Splash.PatchingLabel.Text = "Patching in progress! This may take a moment or two!";
            Thread.Sleep(SleepTime);
            Splash.LoadingBar.Value += 25;

            LoadWeapons(Splash);
            Splash.LoadingBar.Value += 25;
            LoadArmor(Splash);
            Splash.LoadingBar.Value += 25;
            LoadRings(Splash);
            Splash.LoadingBar.Value += 25;
            Splash.PatchingLabel.Text = "Patch Complete!";
        }

我的问题是我的启动画面显示但基于 Thread.Sleep(5000) 而关闭,而不是进度条值等于其最大值。如果我注释掉 Thread.Sleep(5000) 启动画面几乎会立即关闭。在 LoadGearFiles 类中,没有什么特别的,它只是流式读取器/写入器读取和写入记事本文件,将信息加载到数组中。他们成功读/写/填充。此外,在加载齿轮文件类中,我会在读取或写入某些文件后增加进度条的值。我的问题似乎在这里。我应该采取什么样的逻辑/句法方法?

【问题讨论】:

  • 如果您删除您的SplashThread.Abort(); 电话会怎样?或者更直接地说,你为什么要打那个Abort()
  • 您使用的是什么版本的 C#? 4.0+ 有更简单的方法来处理这样的线程情况。
  • 如果我注释掉 SplashThread.Abort();启动画面根本不会关闭。将弹出另一个表单,并且启动画面将留在后台。 @ledbutter 如何检查我使用的是哪个版本?
  • 右键单击您的项目,选择“属性”,在“应用程序”选项卡上有一个“目标框架”组合框,其中显示的值是您正在使用的 C# 版本。

标签: c# multithreading splash-screen


【解决方案1】:

我假设您在代码中使用 WinForms。您似乎希望在最短的时间内显示初始屏幕,或者直到所有文件都成功加载 - 以最后一个为准。

假设您可以访问 C# 4.0 的 Task 和 C# 5.0 的 async/await 关键字,我强烈建议您远离 Thread.Sleep。这是一个相当古老的结构,对于现代多线程程序来说效率不是很高。即使你没有后者,使用Task 也是首选,你会明白为什么你使用它们的次数越多。

让我们把你的逻辑分解成任务:

  1. 显示启动画面。
  2. 异步加载数据文件。
  3. 在 UI 线程上更新进度。
  4. 对每个其他数据文件重复步骤 2-3。
  5. 确保启动画面已显示至少 n 秒。
  6. 关闭启动画面。

让我们以 C# 代码的形式来看看它(我主要是在头脑中编写的,而不是在 IDE 中):

public async void ShowSplashScreen(TimeSpan minimumDuration)
{
    // Show the splash screen to the user.
    var splashScreen = new SplashScreen();
    splashScreen.Show();
    splashScreen.UpdateProgress(0);  // reset progress bar

    // Record when we started to load data for calculating the elapsed time later on.
    var startTime = DateTime.Now;

    // Load all of our data types asynchronously from file.
    var warrior = await LoadDataFileAsync("warrior.dat");
    splashScreen.UpdateProgress(20); // 20%

    var archer = await LoadDataFileAsync("archer.dat");
    splashScreen.UpdateProgress(40); // 40%

    var redMage = await LoadDataFileAsync("redMage.dat");
    splashScreen.UpdateProgress(60); // 60%

    var blueMage = await LoadDataFileAsync("blueMage.dat");
    splashScreen.UpdateProgress(80); // 80%

    var fistWarrior = await LoadDataFileAsync("fistWarrior.dat");
    splashScreen.UpdateProgress(100); // 100% -- all done

    // Determine the elapsed time to load all data files, and the remaining time to display the splash screen.
    var elapsedTime = DateTime.Now - startTime;
    var remainingTimeToWait = minimumDuration - elapsedTime;

    // If we've completed early, wait the remaining duration to show the splash screen.
    if(remainingTimeToWait > TimeSpan.Zero)
      await Task.Delay(remainingTimeToWait);

    // Done loading, close the splash screen.
    splashScreen.Close();
}

现在您的 LoadDataFileAsync 方法看起来像这样:

Task<object> LoadDataFileAsync(string file)
{
    // Do your work to load your data file into an object here.
}

编辑:我收到了关于您正在使用 .NET 4.0 的评论,所以您有 Task 但不一定是 async/await。在这种情况下,您仍然可以将代码分解为 Task,但必须使用 .ContinueWith()

这里有一些很好的例子:How to: Chain Multiple Tasks with Continuations

【讨论】:

  • 一个小问题,但 async/await 直到 C# 5.0 才可用。 Task 在 C# 4.0 中可用。
  • @ledbutter 一个小问题,但Task 与 C# 的版本无关,而与使用的 .NET 版本有关。
  • 感谢您的帮助。太棒了!
  • @user3134679 任何时候,async/await 的东西都很棒。我强烈建议通过将代码分解为基于Task 的块(如果适用)来学习和掌握它。
  • @SiLo 看到 OP 对我的问题的最新评论,关于他正在使用什么版本的 C#(好的,应该是 .NET 框架):他在 .NET 4.0 上,所以 async/await 不是可供他使用。
【解决方案2】:

在 Timer_Tick 中打开您的表单:

void Timer1_Tick(object sender, EventArgs e)
{
    progressBar1.PerformStep();
    if(progressBar1.Value == 100)
    {
        Timer.Enabled = false;
        Form1 form1 = new Form1();
        form1.Show();
        this.Hide(); //or Close maybe (test them both)
    }
}

【讨论】:

  • 谢谢,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多