Question

I try to make my ListBox connected to ObservaleCollection be more efficient so for the DB query I implemented a BackgroundWorker to do the job. Then whithin this backgroundworker I want to add every lets say 70 ms 3 entries to the UI, so the UI on larger number of entries (lets say 100) does not get blocked. Here is the code:

    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]);
            }
        });            
    }

The output is:

SIZE OF TEMP:3

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

in the line: MessagesClass.Instance.Messages.Add(tempM[0]); where the code tries to access the first element of tempM

Any hints whats wrong? Why can't I access the tempM elements, although the collection size is > 0?

Was it helpful?

Solution

You forget about thread synchronization. Look at your code:

            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>();

tempM already will be null when MessagesClass.Instance.Messages.Add(tempM[0]); is executed. So, use some sort or synchronization objects, for example:

            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>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top