首页 > 解决方案 > c#在执行长时间运行的任务时显示流程表单似乎卡住了

问题描述

我正在使用 C# 和 WinForms 创建一个 POS 系统。

我正在使用带有一些文本和图像的表单来指示何时执行长时间运行的过程,例如销售打印和销售后的数据库更新。但是当我这样做时,只显示AjaxLoader表单并且它没有调用它下面的更新函数。

这是我的代码。

public void completeSale()//invoked on Sell button
{
    
    loader = new AjaxLoader();//this is a form
    loader.label1.Text = "Printing...";
    ThreadStart threadStart = new ThreadStart(Execution);
    Thread thread = new Thread(threadStart);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
}

private void Execution()
{
    this.Invoke((MethodInvoker)delegate { loader.ShowDialog(this); });
    Application.DoEvents();

    update_sale("Sold");//method not getting called at all

    this.Invoke((MethodInvoker)delegate { loader.Dispose(); });
}

这是我需要显示的 Ajax 加载程序表单,它应该会阻止我的 POS 表单。因此,在完成打印(执行后台任务)后,我需要关闭加载程序。

Ajax 加载器

问题是线条

Application.DoEvents();
update_sale("Sold");//method not getting called at all

永远达不到。

我究竟做错了什么?

标签: c#winforms

解决方案


表单上的.ShowDialog()是阻塞调用,因此您的代码将等到显示为对话框的表单.Closed()

我还建议使用 using async Task,因为这会使使用Threads变得更加容易!

我已经更改了您的代码以显示这一点。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        await completeSale();
    }

    AjaxLoader loader = null;
    public async Task completeSale()//invoked on Sell button
    {
         //for info, this is how I set up AjaxLoader form properties in the designer.
         loader = new AjaxLoader();
         loader.label1.Text = "Printing...";
         loader.TopMost = true;
         loader.WindowState = FormWindowState.Normal;
         loader.StartPosition = FormStartPosition.CenterParent;
         loader.ShowInTaskbar = false;
         loader.ControlBox = false;
         loader.FormBorderStyle = FormBorderStyle.None;
        //loader.PointToClient(this.DesktopLocation);

        await Execution();   
    }

    private async Task Execution()
    {
        
        if (loader.InvokeRequired)
            this.Invoke((MethodInvoker)delegate { loader.Show(this); });
        else
            loader.Show(this);
        //Application.DoEvents();

        await update_sale("Sold");

        if (loader.InvokeRequired)
            this.Invoke((MethodInvoker)delegate { loader.Close(); });
        else
            loader.Close();
        
    }

    private async Task update_sale(string v)
    {
        //long running process like printing etc..
        await Task.Delay(3000);
    }
}

这将做这样的事情:

在此处输入图像描述

在 AjaxLoader 表单上,我添加了一个进度条,设置为style = Marquee


推荐阅读