【问题标题】:How can I display a loading control while a process is waiting for be finished?如何在进程等待完成时显示加载控件?
【发布时间】:2016-03-18 05:39:30
【问题描述】:

我决定使用这个第三方组件在我的 windows 窗体中制作一个简单的加载控件。

http://www.codeproject.com/Articles/14841/How-to-write-a-loading-circle-animation-in-NET

当在单个请求(每次一个)中打开和关闭将属性“Active”更改为 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;
        }
    }
}

但始终加载显示为没有动画的静态图像。

【问题讨论】:

    标签: c# .net winforms loading


    【解决方案1】:

    您创建一个线程,它只是设置两个属性然后结束。 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.使用异步等待

    这是最简单的一个。

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

    【讨论】:

    • 很好的解释,谢谢@taffer。
    【解决方案2】:

    我建议使用 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;
    }
    

    【讨论】:

    • 你不应该让事件处理程序异步无效并等待 ImportAsync 吗?
    • 两种方式都应该可行,而且我认为两者各有优势。
    猜你喜欢
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    • 2012-03-16
    • 2011-10-07
    • 2010-11-06
    相关资源
    最近更新 更多