0

ObservaleCollection に接続された ListBox をより効率的にしようとするので、DB クエリのために BackgroundWorker を実装してジョブを実行します。次に、このバックグラウンド ワーカー内で、UI に 70 ミリ秒 3 のエントリをすべて追加したいので、多数のエントリ (100 としましょう) の UI はブロックされません。コードは次のとおりです。

    void updateTMWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        var MessagesInDB = from MessageViewModel tm in MessagesDB.Messages
                                  where tm.Type.Equals(_type)
                                  orderby tm.Distance
                                  select tm;

        // Execute the query and place the results into a collection.
        Dispatcher.BeginInvoke(() => { MessagesClass.Instance.Messages = new ObservableCollection<MessageViewModel>(); });

        Collection<MessageViewModel> tempM = new Collection<MessageViewModel>();
        int tempCounter = 0;

        foreach (MessageViewModel mToAdd in MessagesInDB)
        {
            if (MessagesClass.Instance.Messages.IndexOf(mToAdd) == -1)
            {
                tempM.Add(mToAdd);
                tempCounter = tempCounter + 1;
            }
            if (tempCounter % 3 == 0)
            {
                tempCounter = 0;
                Debug.WriteLine("SIZE OF TEMP:" + tempM.Count());
                Dispatcher.BeginInvoke(() =>
                {
                    // add 3  messages at once
                    MessagesClass.Instance.Messages.Add(tempM[0]);
                    MessagesClass.Instance.Messages.Add(tempM[1]);
                    MessagesClass.Instance.Messages.Add(tempM[2]);
                });
                tempM = new Collection<MessageViewModel>();
                Thread.Sleep(70);
            } 
        }
        // finish off the rest
        Dispatcher.BeginInvoke(() =>
        {
            for (int i = 0; i < tempM.Count(); i++)
            {
                MessagesClass.Instance.Messages.Add(tempM[i]);
            }
        });            
    }

出力は次のとおりです。

SIZE OF TEMP:3

A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll

行: MessagesClass.Instance.Messages.Add(tempM[0]); コードが tempM の最初の要素にアクセスしようとする場所

何かヒントはありますか?コレクションのサイズが 0 より大きいのに、tempM 要素にアクセスできないのはなぜですか?

4

1 に答える 1

1

スレッドの同期を忘れています。あなたのコードを見てください:

            1: Debug.WriteLine("SIZE OF TEMP:" + tempM.Count());
            Dispatcher.BeginInvoke(() =>
            {
                // add 3  messages at once
                3: MessagesClass.Instance.Messages.Add(tempM[0]);
                MessagesClass.Instance.Messages.Add(tempM[1]);
                MessagesClass.Instance.Messages.Add(tempM[2]);
            });
            2: tempM = new Collection<MessageViewModel>();

tempMnullが実行されると、すでになりますMessagesClass.Instance.Messages.Add(tempM[0]);。したがって、次のような並べ替えまたは同期オブジェクトを使用します。

            EventWaitHandle Wait = new AutoResetEvent(false);

            Debug.WriteLine("SIZE OF TEMP:" + tempM.Count());
            Dispatcher.BeginInvoke(() =>
            {
                // add 3  messages at once
                MessagesClass.Instance.Messages.Add(tempM[0]);
                MessagesClass.Instance.Messages.Add(tempM[1]);
                MessagesClass.Instance.Messages.Add(tempM[2]);

                Wait.Set();
            });
            // wait while tempM is not in use anymore
            Wait.WaitOne();

            tempM = new Collection<MessageViewModel>();
于 2012-07-04T13:16:51.490 に答える