C#WinForms – 如何在进程等待完成时显示加载控件。 我使用“LoadingCircle”和一个线程
我决定使用这个第三方组件在我的Windows窗体中进行简单的加载控制。
http://www.codeproject.com/Articles/14841/How-to-write-a-loading-circle-animation-in-NET
这在开启和关闭时工作正常,在单个请求中将属性“活动”更改为true或false(每次一个)。 问题是当进程等待服务时,我假装在进程启动之前激活loadingControl,当我“认为”该进程必须完成时关闭。 当我这样做时,图像加载显示为静态图像。 (没有动画)。
对不起这个问题,我是C#的新人。 但我认为我需要使用Threads或类似的东西。
所以我的一般代码是这样的:
using [libraries here]...; namespace [namespace here] { Public partial class Form1 : Form { public Form1() { InitializeComponent(); this.loadingCircle1.Visible = false; } private void button1_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(showLoading)); this.loadingCircle1.Visible = true; t.Start(); //Import an Excel t.Abort(); } public void showLoading() { loadingCircle1.Active = true; loadingCircle1.RotationSpeed = 10; } } }
但是,加载显示为没有动画的静态图像。
您创建一个线程,它只是设置两个属性,然后结束。 t.Abort
可能什么都不做,因为那个时候线程已经退出了。 更糟糕的是,您在UI线程上导入excel文件,该文件会阻止任何动画并冻结整个UI。
这就是你应该如何做到的:
备注:当然,如果您的表单是响应式的,您必须禁用/启用控件并准备好在加载过程中关闭表单时会发生什么情况。
1.使用线程
如果你真的想显式使用线程,那就这样做:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private Thread workerThread = null; private void btnImport_Click(object sender, EventArgs e) { // start the animation (I used a progress bar, start your circle here) progressBar1.Visible = true; progressBar1.Style = ProgressBarStyle.Marquee; // start the job and the timer, which polls the thread btnImport.Enabled = false; workerThread = new Thread(LoadExcel); workerThread.Start(); timer1.Interval = 100; timer1.Start(); } private void LoadExcel() { // some work takes 5 sec Thread.Sleep(5000); } private void timer1_Tick(object sender, EventArgs e) { if (workerThread == null) { timer1.Stop(); return; } // still works: exiting if (workerThread.IsAlive) return; // finished btnImport.Enabled = true; timer1.Stop(); progressBar1.Visible = false; workerThread = null; } }
2.背景工作者
BackgroundWorker
可以在完成时抛出一个事件:
public partial class Form1 : Form { public Form1() { InitializeComponent(); backgroundWorker1.DoWork += BackgroundWorker1_DoWork; backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted; } private void btnImport_Click(object sender, EventArgs e) { // start the animation progressBar1.Visible = true; progressBar1.Style = ProgressBarStyle.Marquee; // start the job btnImport.Enabled = false; backgroundWorker1.RunWorkerAsync(); } private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { LoadExcel(); } private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btnImport.Enabled = true; progressBar1.Visible = false; } private void LoadExcel() { // some work takes 5 sec Thread.Sleep(5000); } }
3.使用async-await
这是最简单的一个。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void btnImport_Click(object sender, EventArgs e) { // start the waiting animation progressBar1.Visible = true; progressBar1.Style = ProgressBarStyle.Marquee; // simply start and await the loading task btnImport.Enabled = false; await Task.Run(() => LoadExcel()); // re-enable things btnImport.Enabled = true; progressBar1.Visible = false; } private void LoadExcel() { // some work takes 5 sec Thread.Sleep(5000); } }
我建议使用async / await(对于C#5.0):
private void button1_Click(object sender, EventArgs e){ ImportAsync(); } private async Task ImportAsync(){ // UI-thread showLoading(); this.loadingCircle1.Visible = true; // wait until task will be finished await Task.Run(() => { // different non-blocking thread for all the hard work, but without UI-stuff // import an Excel }); // going back to UI-thread this.loadingCircle1.Visible = false; }