如何将工作线程上的BindingList绑定到GUI线程C#WinForm上的BindingSource [英] How do I bind a BindingList on worker thread to BindingSource on GUI thread C# WinForm

查看:338
本文介绍了如何将工作线程上的BindingList绑定到GUI线程C#WinForm上的BindingSource的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试绑定BindingList< myobject>这是在工作线程上操作到dataGridView.DataSource。这是我正在尝试做的一个例子。我甚至不确定我尝试做的事情是否正确。我不知道我在这做什么。我得到一个跨线程异常,我(半理解)为什么。我欢迎所有建议和更正。如果有人能指出我正确的方向/设计模式,以便有效和正确地做到这一点,我将不胜感激。



提前致谢,



-DA





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



// 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;
      }

推荐答案

如果控件是由另一个 thread。一般 UI控件(如Label,Button等)都是在主线程上创建的。每当您尝试从工作线程访问UI控件时,您将获得跨线程异常。这就是你获得跨线程异常的原因。


你可以使用 BackgroundWorker 类用于在.Net中执行长时间运行的操作。以下链接可能有助于您了解BackgroundWorker类

http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx [ ^ ]



如果您需要进一步的帮助请告诉我。
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.


嗨David,



不知道这是否仍然适用,但我是现在为货币创建一个类似的应用程序。



我不知道什么是最佳方法。



然而,我遇到了与你自己类似的问题,并为自己找到了解决方案。

我在下面的链接中解释了我的所作所为。使用ThreadedBindingList,它继承自BindingList。我还解释了我为解决我的跨线程异常问题所做的工作,将SyncronizationContext从UI传递到ThreadedBindingList,当时我将它分配给数据源到我的DataGridView。



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

$ / b $ b



原始ThreadedBingingList(我发现)由Marc Gravell在此链接上提供。

https://groups.google.com/forum/# !msg / microsoft.public.dotnet.languages.csharp / IU5ViEsW9Nk / Bn9WgFk8KvEJ





希望如果你仍然有帮助需要它。
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.


这篇关于如何将工作线程上的BindingList绑定到GUI线程C#WinForm上的BindingSource的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆