?
Solved

backgroundworker problem

Posted on 2010-09-12
8
Medium Priority
?
518 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

NFR key for Veeam Backup for Microsoft Office 365

Veeam is happy to provide a free NFR license (for 1 year, up to 10 users). This license allows for the non‑production use of Veeam Backup for Microsoft Office 365 in your home lab without any feature limitations.

Question has a verified solution.

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

A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
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…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…

777 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