多线程的初始屏幕在C#?
-
09-06-2019 - |
题
我想要一个闪屏幕上显示时应用程序。我有一种形式有系统的盘控制系到它。我希望启动屏幕显示虽然这一形式载荷,它需要一点时间因为这是访问网服务API填充一下起伏。我也要做一些基本的测试为依赖在装货之前(即,网服务提供,配置文件的可读).为每个阶段的启动时,我想要更新的初始屏幕与进步。
我已经阅读了很多线程,但我迷失在其中这应该是控制从(在 main()
方法?).我也失踪如何 Application.Run()
工作的,是这里的线为此应建立从?现在,如果形式,与系统的盘控制是"生活"的形式,应该初始从那里来的?它不会不负载直到的形式是完成呢?
我不是在寻找一个代码讲义,更多的算法/办法,所以我可以推测这一次所有:)
解决方案
嗯,所应用程序,我已部署在过去,我们使用 Microsoft.VisualBasic
名字空间,以处理初始屏幕,穿线。你可以参考和使用 Microsoft.VisualBasic
大会从C#。网2.0的,它提供了一个很好的服务。
- 有的主要形式的继承
Microsoft.VisualBasic.WindowsFormsApplicationBase
复盖"OnCreateSplashScreen"的方法,像这样:
protected override void OnCreateSplashScreen() { this.SplashScreen = new SplashForm(); this.SplashScreen.TopMost = true; }
非常简单的,它显示了你的,并在窗体保(这需要创建),同时装货是怎么回事,然后关闭它自动的主要形式已经完成的负载。
这真的会让事情简单, VisualBasic.WindowsFormsApplicationBase
当然是经过良好测试的通过微软以及具有很大的功能,可以让你的生活变得更容易在它,甚至在应用程序是100%。
在一天结束,它是所有IL和 bytecode
无论如何,那么,为什么不用呢?
其他提示
关键是要创建独立的线负责初始屏幕显示。
当你把你的应用程序。净创建了主线程和载荷的规定(主要)的形式。来掩盖苦的工作你可以隐藏的主要形式,直到装载完成。
假设Form1-是你的主要形式,并在窗体保是顶级,borderles漂亮的飞溅形式:
private void Form1_Load(object sender, EventArgs e)
{
Hide();
bool done = false;
ThreadPool.QueueUserWorkItem((x) =>
{
using (var splashForm = new SplashForm())
{
splashForm.Show();
while (!done)
Application.DoEvents();
splashForm.Close();
}
});
Thread.Sleep(3000); // Emulate hardwork
done = true;
Show();
}
后找谷歌和这样的解决方案,这是我最喜欢的:http://bytes.com/topic/c-sharp/answers/277446-winform-startup-splash-screen
FormSplash.cs:
public partial class FormSplash : Form
{
private static Thread _splashThread;
private static FormSplash _splashForm;
public FormSplash() {
InitializeComponent();
}
/// <summary>
/// Show the Splash Screen (Loading...)
/// </summary>
public static void ShowSplash()
{
if (_splashThread == null)
{
// show the form in a new thread
_splashThread = new Thread(new ThreadStart(DoShowSplash));
_splashThread.IsBackground = true;
_splashThread.Start();
}
}
// called by the thread
private static void DoShowSplash()
{
if (_splashForm == null)
_splashForm = new FormSplash();
// create a new message pump on this thread (started from ShowSplash)
Application.Run(_splashForm);
}
/// <summary>
/// Close the splash (Loading...) screen
/// </summary>
public static void CloseSplash()
{
// need to call on the thread that launched this splash
if (_splashForm.InvokeRequired)
_splashForm.Invoke(new MethodInvoker(CloseSplash));
else
Application.ExitThread();
}
}
程序。cs:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
// splash screen, which is terminated in FormMain
FormSplash.ShowSplash();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// this is probably where your heavy lifting is:
Application.Run(new FormMain());
}
}
FormMain.cs
...
public FormMain()
{
InitializeComponent();
// bunch of database access, form loading, etc
// this is where you could do the heavy lifting of "loading" the app
PullDataFromDatabase();
DoLoadingWork();
// ready to go, now close the splash
FormSplash.CloseSplash();
}
我有问题 Microsoft.VisualBasic
解决方案--工作上找到XP,但在Windows server2003终端服务器,主要应用程序的形式出现(后的初始屏幕)的背景和任务栏会闪烁。并带来一个窗口前景/重点放在代码是一个整体的其他可能的蠕虫你可以Google/SO。
这是一个老问题,但我一直碰到它时,试图找到一个螺纹飞溅的画面解决方案WPF可能包括动画。
这里是我的最终拼凑在一起:
应用程序。键
<Application Startup="ApplicationStart" …
应用程序。停靠。cs:
void ApplicationStart(object sender, StartupEventArgs e)
{
var thread = new Thread(() =>
{
Dispatcher.CurrentDispatcher.BeginInvoke ((Action)(() => new MySplashForm().Show()));
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
// call synchronous configuration process
// and declare/get reference to "main form"
thread.Abort();
mainForm.Show();
mainForm.Activate();
}
我建议叫 Activate();
之后直接去 Show();
在回答提供aku.
引用MSDN:
激活的一种形式,它带来的 前如果是这样的活动 应用程序,或者它闪烁的窗口 字幕如果这不是活动 应用程序。形式必须是可见的 对于这种方法有任何效果。
如果你没激活的主要形式,它可以显示 背后 任何其它打开的窗口,使它看起来有点傻。
我认为使用一些方法像 aku的 或 那家伙的 是的路要走,但是一对夫妇的事情要远离的具体实例:
基本的前提就是展现你的飞溅上一个单独的线尽快。这就是我想精益,类似于什么aku的说明,由于这是我最熟悉的。我不知道VB功能的人提及。而且,甚至认为它是一个 VB 库,他是正确的--这是所有的IL在结束。因此,即使感觉 肮脏的 这是不是所有的错!:)我想你会想要确保,无论是VB提供了一个独立的线程中,复盖或者是你自己创建一个-肯定的研究。
假设你在建立另外一个线程,以显示该飞溅,你要小心的交叉线UI更新。我带来这因为你提到的更新的进展。基本上,为了安全起见,你需要叫更新的功能(即创建)在启动形式使用的委托。你通过这一委托的 调用 功能上你的初始屏幕上的形象。事实上,如果你叫飞溅形式直接更新的进度/UI元素,你会得到一个异常提供运行。网2.0CLR。作为一个原则,任何用户界面上的元素的一种形式必须更新在线创建了它-那是什么形式。援引保证.
最后,我可能会选择建立该飞溅的(如果不使用VB载)在主要方法。对我来说,这是更好的比具有的主要形式进行创作的对象和如此紧密结合。如果你采取这种做法,我建议建立一个简单的接口,启动画面实现--什么喜欢IStartupProgressListener--其接收启动的进度更新经由一个部件的功能。这会让你很容易地交换出任何一类需要,并很好地分离的代码。溅形式还可以知道什么时候接近本身,如果您通知时开始是完整的。
一个简单的方法是使用这样的东西作为主():
<STAThread()> Public Shared Sub Main()
splash = New frmSplash
splash.Show()
' Your startup code goes here...
UpdateSplashAndLogMessage("Startup part 1 done...")
' ... and more as needed...
splash.Hide()
Application.Run(myMainForm)
End Sub
时。净CLR开始你的应用程序,它创建了一个'主要'线,并开始执行你的主要()上线。该应用程序。运行(myMainForm)结束时做两件事:
- 开始的Windows的消息泵,使用螺纹,已经执行主()作为GUI线。
- 指定的'主要形式'作为'停形式的应用程序。如果用户的关闭形式,则该应用程序。运行()终止和控制回到你主(),在这里你可以做任何关机你想要的。
没有必要产生一线照顾的飞溅的窗口,而事实上这是一个糟糕的想法,因为那时你会有用的线安全的技术来更新启动内容的自主().
如果你需要其他的线做背景的操作应用程序,则可能产生他们自主().只记得设置线。IsBackground到真实的,所以,他们将死时的主/GUI线的终止。否则你将不得不安排终止所有其他线自己,否则他们会让你的应用程序还活着(但没有GUI)当主线的终止。
我发布了一条关于初始屏幕,以纳入应用程序演示.它是多线程和可能是你感兴趣的
private void MainForm_Load(object sender, EventArgs e)
{
FormSplash splash = new FormSplash();
splash.Show();
splash.Update();
System.Threading.Thread.Sleep(3000);
splash.Hide();
}
我从互联网上的某个地方,但似乎不能再次找到它。简单但有效的。
我喜欢Aku的回答很多,但是代码是为C#3.0,因为它使用一种氧功能。人们需要使用代码在C#2.0,这里的代码使用匿名的委托,而不是lambda功能。你需要一个最上面的winform叫 formSplash
与 FormBorderStyle = None
.的 TopMost = True
参数的形式是重要的,因为启动画面可能看上去像出现然后迅速消失,如果它不是最顶层。我还选择 StartPosition=CenterScreen
因此它看起来像什么一个专业的应用程序将与初始屏幕。如果你想要一个更酷的效果,可以使用 TrasparencyKey
酒店做一个不规则形状的初始屏幕。
private void formMain_Load(object sender, EventArgs e)
{
Hide();
bool done = false;
ThreadPool.QueueUserWorkItem(delegate
{
using (formSplash splashForm = new formSplash())
{
splashForm.Show();
while (!done)
Application.DoEvents();
splashForm.Close();
}
}, null);
Thread.Sleep(2000);
done = true;
Show();
}
我不同意的其他答复建议 WindowsFormsApplicationBase
.以我的经验,它可以减缓你的应用程序。准确地说,虽然它运行形式的构造平行动屏幕推迟您的表格所示的事件。
考虑一个程序(不splashs屏幕)与构造,需要1次和事件的处理程序在所示,带2秒钟。这个程序是使用经过3秒钟。
但是假设你安装了一个闪屏使用 WindowsFormsApplicationBase
.你可能会认为 MinimumSplashScreenDisplayTime
3秒钟的是明智和不会减缓你的应用程序。但是,试一试,你的应用程序现在将需要5秒钟来载荷。
class App : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.MinimumSplashScreenDisplayTime = 3000; // milliseconds
this.SplashScreen = new Splash();
}
protected override void OnCreateMainForm()
{
this.MainForm = new Form1();
}
}
和
public Form1()
{
InitializeComponent();
Shown += Form1_Shown;
Thread.Sleep(TimeSpan.FromSeconds(1));
}
void Form1_Shown(object sender, EventArgs e)
{
Thread.Sleep(TimeSpan.FromSeconds(2));
Program.watch.Stop();
this.textBox1.Text = Program.watch.ElapsedMilliseconds.ToString();
}
结论:不要用 WindowsFormsApplicationBase
如果你程序有一个处理程序上的Slown事件。你可以写更好的代码运行的飞行于两个构造和所示的事件。
实际上mutlithreading在这里是不是有必要的。
让你的商务逻辑产生的一个事件只要你想要的更新启动画面。
然后让你的形式更新启动屏幕因此在方法上钩来处理.
区分的更新可以火不同的活动或提供的数据在一类继承定引.
这种方式可以有很好的改变初始屏幕没有任何多头痛的问题。
实际上这个,你甚至可以支持,例如,gif上的图像一个喷溅形式。为了它的工作,呼应用程序。DoEvents()在您的处理程序:
private void SomethingChanged(object sender, MyEventArgs e)
{
formSplash.Update(e);
Application.DoEvents(); //this will update any animation
}