2

我通过 gps 调制解调器通过 comport 使用以下代码发送 SMS

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 向其他收件人发送短信

4

3 回答 3

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
}

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

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

希望这可以帮助 :)

于 2012-04-05T09:01:10.930 回答
1

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

更新:(汉斯帕桑特提醒我之后)

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

于 2012-04-05T07:14:02.020 回答
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;
        }
    }
于 2012-04-05T22:04:56.730 回答