C# 启动画面等待线程完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/392864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 01:46:25  来源:igfitidea点击:

Splash Screen waiting until thread finishes

c#winformssplash-screen

提问by BDeveloper

I still have a problem with the splash screen. I don't want to use the property SC.TopMost=true.

我的启动画面仍然有问题。我不想使用该属性SC.TopMost=true

Now my application scenario is as follows:

现在我的应用场景如下:

in progeram.cs:

在 progeram.cs 中:

[STAThread]
static void Main()
{
    new SplashScreen(_tempAL);// where _tempAL is an arrayList
    Application.Run(new Form1(_tempAL));
}

in SplashScreen class:

在 SplashScreen 类中:

public SplashScreen(ArrayList _Data)
{
    DisplaySplash()
} 
private void DisplaySplash()
{
    this.Show();
    this.TopMost = true;
    this.CenterToScreen();
    this.SetTopLevel(true);

    _allServerNarrators = new string[10];
    for (int i = 0; i < _allServerNarrators.Length; i++)
        _allServerNarrators[i] = null;

    GetFromServer();

    this.Hide();
    _serverData = new ArrayList();
    _thisData.Add(_allServerNarrators);
    _thisData.Add(_serverNarrators);

}
private void GetFromServer()
{
    _serverNarrators = new ArrayList();
    string _file = "Suras.serverNar";

    if (!Directory.Exists("c:\ASGAQuraan"))
        Directory.CreateDirectory("c:\ASGAQuraan");

    while (counter < 4 && _serverFiles == null)
    {
        if (Download("c:\ASGAQuraan", _ftpServerIP, _file))
        {
            StreamReader _strReader = new StreamReader
                         ("c:\ASGAQuraan\"+_file,System.Text.Encoding.Default);
            string _line = _strReader.ReadLine();
            string _word;

            while (true)
            {
                while (_line != null)
                {
                    _word = _line.Substring(0, _line.IndexOf("*"));
                    int _narId = Convert.ToInt32(_word);
                    _line = _line.Substring(2);
                    int k = 0;
                    _serverNarratorNode = new ArrayList();
                    while (true)
                    {
                        int ind = _line.IndexOf("*");
                        if (ind > 0 && ind < _line.Length)
                        {
                            string str = _line.Substring(0, (ind));
                            if (k == 0)
                            {
                                _allServerNarrators[_narId] = str;
                                _serverNarratorNode.Add(str);
                            }
                            else
                            {
                                _serverNarratorNode.Add(str);
                            }
                            _line = _line.Substring(ind + 1);
                            k++;
                        }
                        else
                        {
                            _line = null;
                            break;
                        }
                    }
                    _serverNarrators.Add(_serverNarratorNode);
                    _serverFiles = "added";
                }
                _line = _strReader.ReadLine();
                if (_line == null)
                {
                    break;
                }
            }
        }
        else
            counter++;
    }
}

What I want is something in the splash screen class which waits until the thread finishes.

我想要的是在启动画面类中等待线程完成的东西。

For more details, please tell me what I need to tell you.

欲了解更多详情,请告诉我我需要告诉你什么。

采纳答案by BDeveloper

Following across 2 threads is a bit confusing, but I'm going to take a stab and say this...

关注 2 个线程有点令人困惑,但我要试一试并说这个......

I don't fully understand your design here, but if the issue is that when you launch a second application the splash screen form turns white... It's most likely due to the fact that splash screen is busy executing all of that code in GetFromServer(). So busy that it has no time to re-paint itself.

我不完全理解你的设计,但如果问题是当你启动第二个应用程序时,启动画面表单变成白色......这很可能是因为启动画面正忙于执行 GetFromServer 中的所有代码()。忙到没时间重新粉刷自己。

To remedy this problem I would suggest that you use the BackGroundWorker componentto execute the GetFromServer method. This will run that method in a separate thread and leave the form's thread free to re-paint itself.

为了解决这个问题,我建议您使用BackGroundWorker 组件来执行 GetFromServer 方法。这将在单独的线程中运行该方法,并使表单的线程可以自由地重新绘制自身。

回答by lc.

You really should give more details about your problem. I could be completely wrong, but I'm going to take a shot in the dark. From what I'm imagining is going on and you want, you want the splash screen to show, do some processing in another thread, then the splash screen to go away when finished.

您确实应该提供有关您的问题的更多详细信息。我可能完全错了,但我要在黑暗中试一试。从我想象的情况来看,您想要显示启动画面,在另一个线程中进行一些处理,然后启动画面在完成后消失。

To do this, you're going to want to move the GetFromServer()call to a BackgroundWorker. Then move the

为此,您需要将GetFromServer()调用移至BackgroundWorker. 然后移动

    this.Hide();
    _serverData = new ArrayList();
    _thisData.Add(_allServerNarrators);
    _thisData.Add(_serverNarrators);

code to the BackgroundWorker_RunWorkerCompletedevent handler.

BackgroundWorker_RunWorkerCompleted事件处理程序的代码。

To use the BackgroundWorker:

要使用BackgroundWorker

1) Initialize the BackGroundWorker

1) 初始化 BackGroundWorker

  BackgroundWorker myWorker = new BackgroundWorker();

2) Add event handlers

2) 添加事件处理程序

  myWorker.DoWork += new DoWorkEventHandler(myWorker_DoWork);
  //put the work you want done in this one

  myWorker.RunWorkerCompleted += 
      new RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted);
  //this gets fired when the work is finished

3) Add code to the event handlers.

3) 向事件处理程序添加代码。

4) Call myWorker.RunWorkerAsync()to start working.

4) 打电话myWorker.RunWorkerAsync()开始工作。

As a separate note, you don't seem to be doing anything with the ArrayListthat you're passing to the splash screen's constructor. Is this intended?

作为单独的说明,您似乎没有对ArrayList传递给启动画面的构造函数的做任何事情。这是故意的吗?

回答by Hans Passant

Same question, same answer:

同样的问题,同样的答案:

The .NET framework has excellent built-in support for splash screens. Start a new WF project, Project + Add Reference, select Microsoft.VisualBasic. Add a new form, call it frmSplash. Open Project.cs and make it look like this:

.NET 框架具有出色的内置闪屏支持。启动一个新的 WF 项目,Project + Add Reference,选择 Microsoft.VisualBasic。添加一个新表单,将其命名为 frmSplash。打开 Project.cs 并使其看起来像这样:

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;

namespace WindowsFormsApplication1 {
  static class Program {
    [STAThread]
    static void Main(string[] args) {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      new MyApp().Run(args);
    }
  }
  class MyApp : WindowsFormsApplicationBase {
    protected override void OnCreateSplashScreen() {
      this.SplashScreen = new frmSplash();
    }
    protected override void OnCreateMainForm() {
      // Do your time consuming stuff here...
      //...
      System.Threading.Thread.Sleep(3000);
      // Then create the main form, the splash screen will close automatically
      this.MainForm = new Form1();
    }
  }
}

回答by Greg D

You've entered dangerous territory by creating UI prior to your call to Application.Run(). Application.Run is essentially your program's message pump. By displaying the UI before you start the application's message pump, you make typical UI interaction effectively impossible on the premature UI. For a splash screen this may not seem relevant, but it will matter if (e.g.) there's a request to make the splash screen disappear if it's clicked on, or you want to use a BackgroundWorker.

通过在调用 Application.Run() 之前创建 UI,您已经进入了危险的领域。Application.Run 本质上是您程序的消息泵。通过在启动应用程序的消息泵之前显示 UI,您可以在不成熟的 UI 上有效地避免典型的 UI 交互。对于启动画面,这似乎无关紧要,但是如果(例如)有一个请求使启动画面在单击时消失,或者您想使用 BackgroundWorker,这将很重要。

These can be worked around by creating a message pump in your splash screen (by making it modal via a call to ShowDialog() instead of Show()), but that's treating the symptom when treating the problem really isn't that difficult.

这些可以通过在启动画面中创建一个消息泵来解决(通过调用 ShowDialog() 而不是 Show() 使其成为模态),但是当处理问题真的不那么困难时,这是治疗症状。

I'd strongly encourage nobugz's answerin this case. The framework provides the support you need. While features in the Microsoft.VisualBasic namespace aren't always very discoverable to C# programmers, they can be a real timesaver and lifesaver for cases like this.

在这种情况下,我强烈鼓励nobugz 的回答。该框架提供了您需要的支持。虽然 Microsoft.VisualBasic 命名空间中的功能对于 C# 程序员来说并不总是很容易发现,但对于此类情况,它们可以真正节省时间和挽救生命。

Good luck!

祝你好运!

回答by Konrad

Unfortunately I don't have enough reputation to comment on someones answer yet. :( This is meant to be the answer to Colonel Panics comment on Hans Passants answer.

不幸的是,我还没有足够的声誉来评论某人的回答。:(这是对恐慌上校对汉斯·帕桑茨回答的评论的回答

His problem was that a MessageBoxshown from new FormMain(args)will be shown behind the splash screen. The key is to invoke the MessageBox from the thread the splash screen runs in:

他的问题是在启动画面后面会显示一个MessageBox显示的new FormMain(args)。关键是从运行启动画面的线程调用 MessageBox:

splashScreen.Invoke(new Action(() => {
    MessageBox.Show(splashScreen, "the message");
}));

Where splashScreenis a reference to the splash screen object that has been created in OnCreateSplashScreenand obviously has to be given to the new Form1object.

哪里splashScreen是对已在其中创建的启动画面对象的引用OnCreateSplashScreen,显然必须将其提供给新Form1对象。