如何在线程结束前禁用控件

时间:2012-04-05 07:03:26

标签: c#

我使用以下代码通过compps通过gps调制解调器发送短信

Thread thread = null;
private void btnsend_Click(object sender, EventArgs e)
    {
        if (thread == null)
        {                
            thread = new Thread(SendSms);
            thread.IsBackground = true;
            thread.Start();
        }
    }
    private void Update(int i)
    {
        if(InvokeRequired)
        {
            this.BeginInvoke(new Action<int>(Update), new Object[] {i});
            return;
        }
        using (var sp = new SerialPort("COM6"))
        {
            sp.Open();
            sp.WriteLine("AT" + Environment.NewLine);
            sp.WriteLine("AT+CMGF=1" + Environment.NewLine);
            sp.WriteLine("AT+CMGS=\"" + dt2.Rows[i]["PhoneNo"] + "\"" + Environment.NewLine);
            sp.WriteLine(tbsms.Text + (char)26);
            if (sp.BytesToRead > 0)
            {
                tbsentto.Text = i + 1 + " of " + dt2.Rows.Count;
            }
        }
    }
    private void SendSms()
    {
        for(int i = 0; i < dt2.Rows.Count; i++)
        {
            Update(i);
            Thread.Sleep(5000);
        }
        thread = null;
    }

我的问题是:如果我的线程正在进行中,我怎么能保持btnsend禁用,以便用户无法按btnsend将短信发送给其他收件人

3 个答案:

答案 0 :(得分:3)

我在自己的一个项目中遇到过类似的问题。

我采用的解决方案如下:

当我为表单上的每个按钮创建后台工作程序时,我为它们分配了DoWork和RunWorkerCompleted工作线程。

然后,在单击按钮时触发的线程上,我还包括一个检查,以确保没有工作线程已经在运行(包括按钮本身触发的线程)。

所以我的代码看起来像这样:

private void XYZ_button_Click(object sender, EventArgs e)
{
    /* Check no background workers are already running */
    if ((XYZ_backgroundworker.IsBusy != true) &&
        (PQR_backgroundworker.IsBusy != true)) /* etc, etc for any other background
        workers you might have */
    {
        XYZ.RunWorkerAsync();
    }
}

private void XYZ_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null) MessageBox.Show("Error: " + e.Error.Message);
    else if (e.Cancelled == true) MessageBox.Show("Canceled!");
}

private void XYZ_DoWork(object sender, DoWorkEventArgs e)
{
    //Your code here
}

我假设您知道如何创建后台工作者,但如果没有,您可以在表单设计页面的工具箱中找到它们。您只需从列表中选择它们,单击要分配给它们的按钮即可!然后,您需要做的就是转到后台工作程序的events属性并分配适当的工作线程。

在您的特定情况下,您需要做的是创建后台工作线程并将btnsend_Click的内容移动到DoWork线程。然后按照我上面使用的格式进行操作。

希望这会有所帮助:)

答案 1 :(得分:1)

您可以调用一个函数,在该操作结束时启用该按钮。这是一种简单的方法。但是如果你想更普遍地处理这个问题,你可以在Thread类上编写一个包装器,或者从Thread类派生一个新类。在新类中,您可以创建在线程动作完成时触发的事件。

更新 :(在Hans Passant提醒我之后)

您可以使用BackGroundWorker。它的作用与我上面解释的方式相同。注册活动WorkerCompleted,该活动将在操作完成后触发。这是一个小example

答案 2 :(得分:1)

我在GeorgePotter的帮助下找到了我的问题的解决方案。非常感谢

private void btnsend_Click(object sender, EventArgs e)
    {
        foreach (Control c in Controls)
        {
            c.Enabled = false;
        }
        if (bgw.IsBusy == false)
        {
            bgw.RunWorkerAsync();
        }
    }
    private void Update(int i)
    {
        if (InvokeRequired)
        {
            this.BeginInvoke(new Action<int>(Update), new Object[] { i });
            return;
        }
        using (var sp = new SerialPort(cbcomport.Text))
        {
            sp.Open();
            sp.WriteLine("AT" + Environment.NewLine);
            sp.WriteLine("AT+CMGF=1" + Environment.NewLine);
            sp.WriteLine("AT+CMGS=\"" + dt.Rows[i]["PhoneNo"] + "\"" + Environment.NewLine);
            sp.WriteLine(tbsms.Text + (char)26);
            if (sp.BytesToRead > 0)
            {
                tbsentto.Text = i + 1 + " of " + dt.Rows.Count;
            }
        }
    }        
    private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            Update(i);
            Thread.Sleep(5000);
        }
    }
    private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        foreach (Control c in Controls)
        {
            c.Enabled = true;
        }
    }