1

datgridview にデータバインドされた BindingList があります。リアルタイムの価格を追跡するために使用しています。メソッド「update(Quote quote)」は、さまざまなスレッドによって 1 秒間に複数回呼び出されます。datagridview に Quote が含まれていない場合は、追加されます。その場合、見積もりの​​値が更新されます。同じ引用符を BindingList (または GUI) に 2 回表示したくないので、値がリストにあるかどうかをチェックする操作をロックしようとしました。うまくいきません!私は何を間違っていますか?2 つの異なるロック方法を試しましたが、単なるオブジェクトではなく 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);
     }
}

これについて何か助けていただければ幸いです。

ありがとう。

4

2 に答える 2

8

私が前に書いたこのコードは

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; }
    }
}
于 2012-09-21T15:57:46.190 に答える
2

に変更する必要があると思いBeginInvokeますInvoke。非同期操作を開始するのではなく、UI スレッドで取得する必要があります。BeginInvokeそうしないと、 を呼び出すとすぐに制御が返されるため、ターゲットが呼び出される前にロックが解放される可能性がありますBeginInvoke。呼び出しInvokeは、Invoke ターゲットが完了するまでその呼び出しでそのスレッドをブロックし、制御をスレッドに戻します。これにより、ロックが確実に保持されます。

また、メソッド呼び出しlockの代わりにブロックを使用することを検討しましたか? Monitor基本的には同じですが、try/finally が不要になります。再試行を使用したり、 を利用したりしているようには見えませんTryEnterが、コード サンプルではそれが示されていない可能性があります。

于 2012-09-21T14:51:29.807 に答える