初始屏幕在完成更新标签的所有步骤之前不会显示
本文关键字:有步骤 显示 标签 屏幕 更新 | 更新日期: 2023-09-27 18:35:03
我已经为WinForm应用程序创建了一个初始屏幕。 一切都运行良好,直到初始屏幕只是一个带有背景图像和具有静态文本的标签的窗体 - "正在加载...">
我想用文本不断更新标签(中间有小延迟( - "正在加载","正在加载","正在加载..."和"正在加载..."。为此,我将以下代码放在我的SplashScreen
形式中:
private void SplashScreen_Load(object sender, EventArgs e)
{
lblLoading.Refresh();
lblLoading.Text = "Loading.";
Thread.Sleep(500);
lblLoading.Refresh();
lblLoading.Text = "Loading..";
Thread.Sleep(500);
lblLoading.Refresh();
lblLoading.Text = "Loading...";
Thread.Sleep(500);
}
现在,在初始屏幕中的标签更新为"正在加载..."之前,初始屏幕不会显示。
请帮助让我知道我做错了什么。我HomeScreen
中的代码:
public HomeScreen()
{
//....
this.Load += new EventHandler(HandleFormLoad);
this.splashScreen = new SplashScreen();
}
private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();
Thread thread = new Thread(new ThreadStart(this.ShowSplashScreen));
thread.Start();
//...Performing tasks to be done while splash screen is displayed
done = true;
this.Show();
}
private void ShowSplashScreen()
{
splashScreen.Show();
while (!done)
{
Application.DoEvents();
}
splashScreen.Close();
this.splashScreen.Dispose();
}
编辑:
正如这里的一些用户所建议的那样,我将启动任务放在后台线程中,现在我正在显示主线程中的启动画面。但同样的问题仍然存在。以下是表单HomeScreen
更新的代码:
public HomeScreen()
{
//...
this.Load += new EventHandler(HandleFormLoad);
}
private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();
SplashScreen sc = new SplashScreen();
sc.Show();
Thread thread = new Thread(new ThreadStart(PerformStartupTasks));
thread.Start();
while (!done)
{
Application.DoEvents();
}
sc.Close();
sc.Dispose();
this.Show();
}
private void PerformStartupTasks()
{
//..perform tasks
done = true;
}
这是Splash Screen
:
private void SplashScreen_Load(object sender, EventArgs e)
{
lblLoading.Update();
lblLoading.Text = "Loading.";
Thread.Sleep(500);
lblLoading.Update();
lblLoading.Text = "Loading..";
Thread.Sleep(500);
lblLoading.Update();
lblLoading.Text = "Loading...";
Thread.Sleep(500);
}
您需要一个发布 ProgressChanged 事件的 BackgroundWorker ,该事件将更新初始屏幕。进度更改的对象可以是字符串,例如,您将在初始屏幕上显示该字符串(返回到 GUI 线程上(。
您应该在主线程中处理初始屏幕,并在后台线程中处理初始化的后台工作(正如逻辑学家所评论的那样(。
也就是说,更改的消息未显示的原因是主线程繁忙,因此它不处理重绘控件的事件。在后台线程中调用DoEvents
将仅处理该线程中的消息,并且用于更新初始屏幕的消息位于主线程中。
Refresh
方法仅使控件失效,如果主线程处理事件,这将导致重绘控件。可以使用 Update
方法强制重绘控件:
private void SplashScreen_Load(object sender, EventArgs e)
{
lblLoading.Text = "Loading.";
lblLoading.Update();
Thread.Sleep(500);
lblLoading.Text = "Loading..";
lblLoading.Update();
Thread.Sleep(500);
lblLoading.Text = "Loading...";
lblLoading.Update();
}
但是,这只是当前代码的解决方法。你真的应该让主线程处理消息。
感谢大家回答我的问题。终于解决了我的问题!我更改了我的代码,以便现在在单独的线程上执行启动任务,并且从主屏幕(主(线程显示初始屏幕。在主屏幕中,我利用Backgroundworker
更新"正在加载..."。标签。
我在这里发布我的代码,希望它将来也能帮助某人。
有关Home Screen
代码,请参阅我问题中的编辑部分。这是Splash Screen
的代码:
public SplashScreen()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = false;
lblLoading.Text = string.Empty;
}
private void SplashScreen_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
for (int i = 1; i <= 20; i++)
{
System.Threading.Thread.Sleep(200);
worker.ReportProgress(i);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string dots = string.Empty;
for (int k = 1; k <= e.ProgressPercentage; k++)
{
dots = string.Format("{0}..",dots);
}
lblLoading.Text = ("Loading" + dots);
}
您必须在初始屏幕窗体中定义后台辅助角色。
下面是初始屏幕的外观示例:
public partial class SplashScreenForm<T> : Form
{
private BackgroundWorker _backgroundWorker;
private Func<BackgroundWorker, T> _func;
private T _funcResult;
public T FuncResult { get { return _funcResult; } }
public SplashScreenForm(Func<BackgroundWorker, T> func)
{
this._func = func;
InitializeComponent();
this.label1.Text = "";
this._backgroundWorker = new BackgroundWorker();
this._backgroundWorker.WorkerReportsProgress = true;
this._backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
this._backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
this._backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
_backgroundWorker.RunWorkerAsync();
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
if (worker != null)
{
_funcResult = this._func.Invoke(worker);
}
}
private void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState != null)
{
this.label1.Text = e.UserState.ToString();
}
}
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Close();
}
}
你可以按照你想要的方式设计它,也许是一个漂亮的gif图像,或者你能想到的任何东西。
这样称呼它:
private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();
var splash = new SplashScreenForm<bool>(PerformTask);
splash.ShowDialog(); // function PerformTask will be launch at this moment
this.Show();
}
private bool PerformTask(BackgroundWorker worker)
{
//...Performing tasks to be done while splash screen is displayed
worker.ReportProgress("loading..");
}