Click here to Skip to main content
15,070,111 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to bind a BindingList<myobject> that's manipulated on a worker thread to a dataGridView.DataSource. Here's an example of what I'm trying to do. I'm not even sure if what I'm "trying" do is the correct way to go about this. I have no idea of what I'm doing here. I'm getting a cross thread exception and I (semi-understand) why. I welcome ALL suggestions and corrections. Would appreciate if someone would point me in the right direction/design pattern to implement in order to do this efficiently and correctly.

Thanks in advance,

-DA


public class Stock : INotifyPropertyChanged
  {
      private string symbol;
      private double price;
      private int    size;

      public event PropertyChangedEventHandler PropertyChanged;

      public Stock(string symbol, double price, int size)
      {
          this.symbol = symbol;
          this.price = price;
          this.size = size;
      }

      public string Symbol
      {
          get { return symbol; }
      }

      public double Price
      {
          get { return price; }
          set
          {
              if (price != value)
              {
                  price = value;
                  OnPropertyChanged("Price");
              }
          }
      }

      public int Size
      {
          get { return size; }
          set
          {
              if (size != value)
              {
                  size = value;
                  OnPropertyChanged("Size");
              }
          }
      }

      private void OnPropertyChanged(string propertyName)
      {
          if(PropertyChanged != null)
              PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
  }


public class StocksManager
 {
     // Members
     int NUM_PROCESSORS = Environment.ProcessorCount;

     MktDataSim                mktData;
     List<Thread>              workers;
     EventWaitHandle           signal;
     Queue<Stock>              workQueue;
     object                    sync;
     BindingList<Stock>        stocksCollec;

     // Constructor
     public StocksManager()
     {
         mktData          = new MktDataSim();
         workers          = new List<Thread>();
         signal           = new AutoResetEvent(false);
         workQueue        = new Queue<Stock>();
         sync             = new object();
         stocksCollec     = new BindingList<Stock>();

         mktData.StockUpdateHandler += new StockUpdateEventHandler
             (mktData_StockUpdateHandler);

         for (int i = 0; i < NUM_PROCESSORS; i++)
         {
             workers.Add(new Thread(worker));
             workers[i].IsBackground = true;
             workers[i].Start();
         }
     }

     // Properties
     public BindingList<Stock> StockCollection
     {
         get { return stocksCollec; }
     }

     // Methods/Event Handlers
     private void mktData_StockUpdateHandler(string symbol, double price, int size)
     {
         getMktData(new Stock(symbol, price, size));
     }


     private void getMktData(Stock stock)
     {
         lock (sync)
             workQueue.Enqueue(stock);
         signal.Set();
     }

     private void worker()
     {
         while (true)
         {
             Stock stock = null;

             lock (sync)
             {
                 if (workQueue.Count > 0)
                     stock = workQueue.Dequeue();
             }

             if (stock != null)
             {
                 string sym = stock.Symbol;
                 double prc = stock.Price;
                 int    sz  = stock.Size;

                 // I'm TRYING to only add new stocks
                 // but this isn't working because I
                 // can't distinguish by symbol
                 if (!stocksCollec.Contains(stock))
                 {
                     stocksCollec.Add(new Stock(sym,prc,sz));
                 }
                 else
                 {
                     int elmnt = stocksCollec.IndexOf(stock);
                     stocksCollec[elmnt].Price = prc;
                     stocksCollec[elmnt].Size  = sz;
                 }
             }
             else
             {
                 signal.WaitOne();
             }
         }
     }
}


// GUI
public partial class Form1 : Form
  {
      StocksManager stkMngr;
      BindingSource stocksDataSource;

      public Form1()
      {
          InitializeComponent();

          stkMngr          = new StocksManager();

          // I'm using a bindingSource because
          // I'll need to be able to manipulate
          // my list of objects i.e. (sorting, removing,
          // updating, and deleting)
          stocksDataSource = new BindingSource();
          stocksDataSource.DataSource = stkMngr.StockCollection;
          dgvDisplay.DataSource = stocksDataSource;
      }
Posted
Updated 20-Feb-12 0:46am

We cannot perform operation on a control, if that control was created by another thread. Generally UI Controls like Label, Button, etc. are created on Main Thread. Whenever you try to access UI control from worker thread you will get cross thread exception. This is the reason you are getting cross thread exception.

You can use BackgroundWorker class for performing long running operation in .Net. Following link might help you to understand BackgroundWorker class
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx[^]

If you need further help please let me know.
   
Comments
d.allen101 20-Feb-12 7:07am
   
I understand the cross threading issue. what's i'm trying to find out is how do I properly implement this. can you give me an example of how to go about manipulating the objects bindingList on a worker thread and having those results reflected in my GUI's dataGridView control when changes are made to my object bindingList.
Hi David,

Don't know if this still applies, but I'm creating a similar type of application, right now for Currencies.

I don't know what would be the optimal approach either.

However, I hit upon a similar issues as yourself, and found a solution for myself.
I explain what I did in the link below. Employing a ThreadedBindingList, which inherits from BindingList. I also explain what I did to resolve my Cross-thread Exception issue, by passing the SyncronizationContext from the UI to the ThreadedBindingList at the time that I assigned it to the datasource to my DataGridView.

http://stackoverflow.com/questions/30425283/binding-source-not-reflecting-new-removed-row-when-list-datasource-adds-removes/30446089#30446089



The Original ThreadedBingingList (that I found) was given by Marc Gravell on this link.
https://groups.google.com/forum/#!msg/microsoft.public.dotnet.languages.csharp/IU5ViEsW9Nk/Bn9WgFk8KvEJ


Hope this helps if you still need it.
   
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900