[Last Call] Learn about multicloud storage options and how to improve your company's cloud strategy. Register Now

x
?
Solved

backgroundworker problem

Posted on 2010-09-12
8
Medium Priority
?
522 Views
Last Modified: 2013-11-10
On a windows form I have 3 comboboxes being filled asynchronously.
When a form is loaded one combobox is filled with items from a sql-table which uses a query like : select * from tbl where name like 'A%'.
If I now click on eg button B I want this combobox being filled with a query like ... where name like 'B%'.
But for some reason this does not work it errors with : cross-thread operation not vaild.

(It errors on FillComboFromStringCollection2 on cobo.items.Add(item))

Can anyone please have a look, I don't understand a lot of these backgroundworkers.

private void MemoWindow_Load(object sender, EventArgs e)
        {
            sqlInfoFetcher = new BackgroundWorker();
            sqlInfoFetcher.DoWork += new DoWorkEventHandler(sqlInfoFetcher_DoWork);
            sqlInfoFetcher.RunWorkerCompleted += new RunWorkerCompletedEventHandler(sqlInfoFetcher_RunWorkerCompleted);
           
            sqlInfoFetcher.RunWorkerAsync();
        }

 private void btnA_Click(object sender, EventArgs e)
        {
            sqlInfoFetcher2 = new BackgroundWorker();
            sqlInfoFetcher2.DoWork += new DoWorkEventHandler(sqlInfoFetcher2_DoWork);
            sqlInfoFetcher2.RunWorkerCompleted += new RunWorkerCompletedEventHandler(sqlInfoFetcher2_RunWorkerCompleted);
            sqlInfoFetcher2.RunWorkerAsync();
        }

 void sqlInfoFetcher2_DoWork(object sender, DoWorkEventArgs e)
        {
            string connectionString = "Data Source=CLUSTER;Initial Catalog=Contacts;user id=sa;password=sa; Asynchronous Processing=true";
            string query = "SELECT DISTINCT First_Name + ' ' + Last_Name AS Expr1 FROM         dbo.NAME WHERE     (Last_Name LIKE 'B%')";
            e.Result = FetchDataFromDB(connectionString, query);
        }
        void sqlInfoFetcher2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            FillComboFromStringCollection2(cboToExternal, e.Result as StringCollection);
        }
        void sqlInfoFetcher_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            FillComboFromStringCollection(cboToExternal, e.Result as StringCollection);
        }

        void sqlInfoFetcher_DoWork(object sender, DoWorkEventArgs e)
        {
            string connectionString = "Data Source=CLUSTER;Initial Catalog=Contacts;user id=sa;password=sa; Asynchronous Processing=true";
            string query = "SELECT DISTINCT First_Name + ' ' + Last_Name AS Expr1 FROM         dbo.NAME WHERE     (Last_Name LIKE 'A%')";
            e.Result = FetchDataFromDB(connectionString, query);
        }


  private void FillComboFromStringCollection(ComboBox combo, StringCollection items)
        {
            foreach (string item in items)
            {
                combo.Items.Add(item);
            }
            combo.Enabled = true;
        }
        private StringCollection FetchDataFromDB(string connectionString, string query)
        {
            SqlCommand command = null;
            SqlConnection connection = null;
            SqlDataReader reader = null;
            StringCollection results = new StringCollection();
            try
            {

                connection = new SqlConnection(connectionString);
                command = new SqlCommand(query, connection);
                command.CommandTimeout = 0;
                connection.Open();
                reader = command.ExecuteReader(CommandBehavior.CloseConnection);
                while (reader.Read())
                {
                    results.Add(reader.GetString(0));
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            finally
            {
                command = null;
                if (reader != null) reader.Close();
                if ((connection != null) && (connection.State != ConnectionState.Closed))
                    connection.Close();
                reader = null;
                connection = null;
            }
            return results;
        }


        private void FillComboFromStringCollection2(ComboBox combo, StringCollection items)
        {
            foreach (string item in items)
            {
                combo.Items.Add(item);
            }
            combo.Enabled = true;
        }

Open in new window

0
Comment
Question by:dekempeneer
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
8 Comments
 
LVL 10

Expert Comment

by:james-ct16
ID: 33659962
Howdy

This problem is by design to stop non ui thread from making changes to the controls. The good news is though there is a nice pattern to follow to solve this problem.

Below is a link to an MSDN walk though example using the background worker object and setting values in a win forms control.
http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx

Hope this helps

James
0
 

Author Comment

by:dekempeneer
ID: 33660042
Ok, but what I can do with my code then ??
For all I understand it looks good.
0
 
LVL 10

Expert Comment

by:joriszwaenepoel
ID: 33660060
I don't see what is wrong with the code at first glance.

However, does it really take such a long time to fill the combobox, that it needs to be done on a background thread.  It seems that in this case it just makes your code much more complicated.

Are you sure you need " Asynchronous Processing=true " in the connection string?  I have never used that, and you are not doing async processing (which would be using BeginExecuteReader instead of ExecuteReader).
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 10

Accepted Solution

by:
james-ct16 earned 2000 total points
ID: 33660073
Howdy

The code below should get you on the way. So I have created the delegate that you will invoke to switch from the background thread to the ui thread.

Hope that helps

James
/// <summary>
        /// Callback delegate, we will use this to get back to the ui thread
        /// </summary>
        private delegate void FillCombo(ComboBox combo, StringCollection items);

        /// <summary>
        /// Fills the combo from string collection2.
        /// </summary>
        /// <param name="combo">The combo box</param>
        /// <param name="items">The collection of items</param>
        private void FillComboFromStringCollection2(ComboBox combo, StringCollection items)
        {
            if (combo.InvokeRequired)
            {
                FillCombo d = new FillCombo(this.FillComboFromStringCollection2);
                this.Invoke(d, combo, items);
                return;
            }

            foreach (string item in items)
            {
                combo.Items.Add(item);
            }

            combo.Enabled = true;
        }

Open in new window

0
 
LVL 10

Expert Comment

by:james-ct16
ID: 33660086
joriszwaenepoel does make a very good point which I missed just answering your question, why go to the trouble of using a background worker thread (ok so its not that much work) when its built in for you in the async execute readers as documented at

http://msdn.microsoft.com/en-us/library/1a674khd.aspx

They provide a couple of nice worked examples as well.

James
0
 

Author Comment

by:dekempeneer
ID: 33660110
James,
thx, that code works.
I'll look into that async sql reader.
And yes it takes a while to load up > 50000 items from sql :)

0
 
LVL 10

Expert Comment

by:joriszwaenepoel
ID: 33660203
Actually,

1. The backgroundworker was created to avoid the need to use techniques like the one in the solution (delegate, InvokeRequired, etc..).  The RunWorkerCompleted event should be raised on the correct thread automatically.  I don't see why it doesn't in your example, but it should.

2. If you want to speed up the filling of the combobox, you can look at using "combo.Items.AddRange" instead of "combo.Items.Add", andalso call "BeginUpdate" before you start filling it, and "EndUpdate" when you are done.

3. Do you have an index on the LAST_NAME column in your database?  This would improve the speed of reading from the DB.

4.  A combobox with that much items is probably very difficult to use.   Maybe you should consider to create another filter to limit the amount of data in the comboboxes.
0
 

Author Comment

by:dekempeneer
ID: 33660220
1. Ok, but for now it works. I will have a look at it comparing it with examples for msdn allthough I alwyas find it hard to do that as MSDN usually uses the most simple examples.
2. It is ok now as I do it by using alphabet-buttons so not all 50000 are being loaded into the combobox, only the ones that start with eg A, B, C, ...
3. This is an old database and will be adapted in November to a CRM-system so who knows what the future brings
4. See 2.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…

650 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question