1

我是线程新手,我收到了这个错误

跨线程操作无效:控件“comboBoxLocation”从创建它的线程以外的线程访问。

我不知道我是否正确创建了这个线程,但每次它都给我这个错误。有谁知道如何解决这个问题。我已经尝试过:

this.Invoke(new MethodInvoker(delegate()
{
     da.SelectCommand.Parameters.AddWithValue("@QueueID", comboBoxLocation.SelectedValue.ToString());
}));

而且我仍然收到该错误。

string branch;
SpeechSynthesizer reader = new SpeechSynthesizer();
Thread t;
bool flag;

//SqlDataReader dr2;
public Main()
{
    InitializeComponent();
}

private void btnStart_Click(object sender, EventArgs e)
{
    lblStatus.Text = "Started!";
    btnStop.Enabled = true;
    btnStart.Enabled = false;
    t = new Thread(Begin); //calls Begin method
    t.Name = "Queue"; //thread name
    t.Start(); //Starts thread
    flag = false;
    branch = comboBoxLocation.SelectedValue.ToString();
}

private void btnStop_Click(object sender, EventArgs e)
{
    lblStatus.Text = "Voice Application Termintated!";
    btnStart.Enabled = true;
    btnStop.Enabled = false;
    t.Abort(); //Kills Thread
    flag = true;
}     

//Began method
public void Begin()
{
    double announce;
    double announceID;

    string Stringannounce;
    string ticketNum, station, id, displaynum;
    string speak;

    try
    {
        using (SqlConnection connStr = new SqlConnection(ConfigurationManager.ConnectionStrings["AnnounceConnString"].ConnectionString))
        {
            while (true)
            {
               //Selects Last record written to tblAnnounce 
                SqlCommand sqlcommandStart = new SqlCommand("SELECT id, AnnounceID, AddDate FROM tblAnnounce ORDER by AddDate ASC", connStr);
                connStr.Open();

                SqlDataReader dr = sqlcommandStart.ExecuteReader();

                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Stringannounce = dr["AnnounceID"].ToString();
                        announceID = Convert.ToDouble(Stringannounce);


                        SqlDataAdapter da = new SqlDataAdapter("SELECT TOP 1 id, qdate, ticket_number, QueueID, received, displaynum, station, transcodevoiced FROM vwAnnounce WHERE QueueID = @QueueID ORDER by received ASC", connStr);
                        //da.SelectCommand.CommandType = CommandType.StoredProcedure;

                        DataSet ds = new DataSet();
  *****************da.SelectCommand.Parameters.AddWithValue("@QueueID", comboBoxLocation.SelectedValue.ToString());***** //ERROR HERE
                        da.Fill(ds);

                        DataTable dt = new DataTable();
                        dt = ds.Tables[0];


                        foreach (DataRow dr2 in dt.Rows)
                        {
                            id = dr2["id"].ToString();
                            announce = Convert.ToDouble(id);
                            ticketNum = dr2["ticket_number"].ToString();
                            station = dr2["station"].ToString();
                            //transcodevoiced = dr2["transcodevoiced"].ToString();
                            displaynum = dr2["displaynum"].ToString();
                            SplitString splitter = new SplitString(displaynum);
                            splitter.Split();

                            if (announceID == announce)
                            {
                                // Set a value for the speaking rate.
                                reader.Rate = -4;
                                // Set the volume of the SpeechSynthesizer's ouput.
                                reader.Volume = 85;
                                //String that will be spoken
                                speak = "Now, " + displaynum + ", at #" + station;

                                //The problem with the Speak() function is that it is not threaded, so we use SpeakAsync(). It means that you cannot perform any other function in your windows form until the "reader" object has completed the speech.
                                reader.SpeakAsync(speak);
                                //Pauses system for 1 seconds after voice completion
                                Thread.Sleep(3000);

                                //Deletes record from Database table tblAnnounce
                                SqlCommand delete = new SqlCommand("DELETE FROM tblAnnounce WHERE AnnounceID = @announceID ", connStr);
                                delete.Parameters.AddWithValue("@announceID", announceID);
                                delete.ExecuteNonQuery();
                                reader.Resume();
                            }
                        }                                            
                    }
                    connStr.Close();
                }                       
                dr.Close();
            }
        }
    }
    catch(Exception ex)
    {
        string exception = ex.Message;
    }
}
4

2 回答 2

1

为了解决你的问题,Invoke应该放在下面的行:

    comboBoxLocation.Invoke(
new Action(() => branch = comboBoxLocation.SelectedValue.ToString()); 

希望这有帮助。

于 2013-05-31T16:45:03.137 回答
0

您正在通过表单而不是控件调用。

用这个:

comboBoxLocation.Invoke(new MethodInvoker(delegate()
{
     da.SelectCommand.Parameters.AddWithValue("@QueueID", comboBoxLocation.SelectedValue.ToString());
}));

改为通过控件调用。

这是来自 Microsoft 的线程安全调用的一个很好的资源。

http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

为了改进您的代码,您还可以在执行此操作之前检查是否需要调用。例子:

if (comboBoxLocation.InvokeRequired)
{
     comboBoxLocation.Invoke(
          (MethodInvoker)
               delegate {
                    da.SelectCommand.Parameters.AddWithValue("@QueueID", comboBoxLocation.SelectedValue.ToString());
});
else
{
     da.SelectCommand.Parameters.AddWithValue("@QueueID", comboBoxLocation.SelectedValue.ToString());
}
于 2013-05-31T16:56:47.943 回答