基于进度条的启动屏幕未关闭

时间:2014-01-02 20:51:19

标签: c# multithreading splash-screen splash

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();

        }

LoadGearFiles.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类中,没有什么特别之处,只是流读取器/写入器读取和写入记事本文件,将信息加载到数组中。他们成功地读/写/填充。此外,在装载齿轮文件类中,我在读取或写入某些文件后增加进度条的值。这里似乎是我的问题。我应该采取什么样的逻辑/句法方法?

2 个答案:

答案 0 :(得分:1)

我假设您正在使用代码中的WinForms。看起来您希望在最短时间内显示启动画面,或者直到所有文件都成功加载 - 以最后为准。

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

让我们将你的逻辑分解为任务:

  1. 显示启动画面。
  2. 异步加载数据文件。
  3. 更新UI线程的进度。
  4. 对每个附加数据文件重复步骤2-3。
  5. 确保至少 n 秒显示启动画面。
  6. 关闭启动画面。
  7. 让我们以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

答案 1 :(得分:1)

在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)
    }
}