Skip to main content
 首页 » 编程设计

c#之为绑定(bind)列表/跨线程和锁定问题异步添加值

2024年01月21日26birdshome

我有一个绑定(bind)到 datgridview 的 BindingList 数据。我用它来跟踪一些实时价格。各种线程每秒多次调用方法“update(Quote quote)”。如果 datagridview 不包含 Quote,则会添加它。如果是,则更新报价的值。我不希望相同的引号出现在 BindingList (或 GUI 上)两次,所以我尝试锁定检查值是否在列表中的操作。它不起作用!我究竟做错了什么?我尝试了两种不同的锁定方式,并且锁定在 String 对象上,而不仅仅是一个对象。问题肯定出在BeginInvoke(new MethodInvoker(delegate() { activeQuotes.Insert(0, quote); }));调用(这可能需要一些时间),但如果我进行同步,“添加”方法会引发“跨线程”错误。 . .我能做些什么来避免跨线程错误,但确保锁也可以工作?

public BindingList<Quote> activeQuotes = new BindingList<Quote>(); 
object lockObject = "lockObject"; 
 
dataGridViewActive.DataSource = activeQuotes; 
 
 
public void update(Quote quote) 
{ 
//lock (lockObject) 
if(Monitor.TryEnter(lockObject)) 
{ 
try 
   { 
    if (!activeQuotes.Contains(quote)) 
    { 
       try 
       { 
          activeQuotes.Add(quote); 
          AddQuote(quote); 
       } 
       catch (Exception ex) 
       { 
          Console.WriteLine("Datagridview!!!!!!"); 
       } 
     } 
 else 
 { 
   int index = activeQuotes.IndexOf(quote); 
   activeQuotes[index].Bid = quote.Bid; 
   activeQuotes[index].Ask = quote.Ask; 
   activeQuotes[index].Mid = quote.Mid; 
   activeQuotes[index].Spread = quote.Spread; 
   activeQuotes[index].Timestamp = quote.Timestamp; 
} 
finally 
{ 
    Monitor.Exit(lockObject); 
} 
} 
 
private void AddQuote(Quote quote) 
{ 
     if (this.InvokeRequired) 
     { 
                BeginInvoke(new MethodInvoker(delegate() { activeQuotes.Insert(0, quote); })); 
                BeginInvoke(new MethodInvoker(delegate() { dataGridViewActive.Refresh(); })); 
                BeginInvoke(new MethodInvoker(delegate() { dataGridViewActive.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); })); 
    } 
    else 
    { 
                activeQuotes.Add(quote); 
                dataGridViewActive.Refresh(); 
                dataGridViewActive.AutoResizeColumns (DataGridViewAutoSizeColumnsMode.AllCells); 
     } 
} 

我很感激这方面的任何帮助。

谢谢。

请您参考如下方法:

我之前写的这段代码会做

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
        BindingListInvoked<Name> names; 
 
        public Form1() 
        { 
            InitializeComponent(); 
        } 
 
        private void Form1_Load(object sender, EventArgs e) 
        { 
            names = new BindingListInvoked<Name>(dataGridView1); 
 
            dataGridView1.DataSource = names; 
 
            new Thread(() => names.Add(new Name() { FirstName = "Larry", LastName = "Lan" })).Start(); 
            new Thread(() => names.Add(new Name() { FirstName = "Jessie", LastName = "Feng" })).Start(); 
        } 
    } 
 
    public class BindingListInvoked<T> : BindingList<T> 
    { 
        public BindingListInvoked() { } 
 
        private ISynchronizeInvoke _invoke; 
        public BindingListInvoked(ISynchronizeInvoke invoke) { _invoke = invoke; } 
        public BindingListInvoked(IList<T> items) { this.DataSource = items; } 
        delegate void ListChangedDelegate(ListChangedEventArgs e); 
 
        protected override void OnListChanged(ListChangedEventArgs e) 
        { 
 
            if ((_invoke != null) && (_invoke.InvokeRequired)) 
            { 
                IAsyncResult ar = _invoke.BeginInvoke(new ListChangedDelegate(base.OnListChanged), new object[] { e }); 
            } 
            else 
            { 
                base.OnListChanged(e); 
            } 
        } 
        public IList<T> DataSource 
        { 
            get 
            { 
                return this; 
            } 
            set 
            { 
                if (value != null) 
                { 
                    this.ClearItems(); 
                    RaiseListChangedEvents = false; 
 
                    foreach (T item in value) 
                    { 
                        this.Add(item); 
                    } 
                    RaiseListChangedEvents = true; 
                    OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); 
                } 
            } 
        } 
    } 
 
    public class Name 
    { 
        public string FirstName { get; set; } 
        public string LastName { get; set; } 
    } 
}