0

I have a method in a thread that pulls user images, and tie the images to an ItemCollection list. while the images are being pulled, I want to be able to search through the list. I keep getting this error, Collection was modified; enumeration operation may not execute. Here is the image pulling code:

Thread reprintAppsThread = new Thread(() =>
    {
        var items = assignmentPage.reprintItemListView.Items;
        foreach (EcofOApplicationObject obj in items)
        {
            byte[] userPassport;
            bool fetched = userPassports.TryGetValue(obj.TrackCode, out userPassport);

            if (!fetched && !obj.fetchingThumbnail) /*&& (obj.userPassportBytes == null || 
              obj.userPassportBytes.Length == 0))*/
            {
                while (thumbnailThreadCount >= 20)
                {
                    Thread.Sleep(2000);
                }

                thumbnailThreadCount++;

                Thread newT = new Thread(() => { fetchThumbnailsAsync(obj); });
                newT.Start();
            }

            else
            {
                m_log.DebugFormat("Matching {0} to its passport", obj.TrackCode);
                obj.userPassportBytes = userPassport;
            }
        }


    });
        newAppsThread.SetApartmentState(ApartmentState.STA);
        newAppsThread.Start();
        reprintAppsThread.Start();

    }

Here is the search code:

private void ShowSearchList()
        {
            searchButton.IsEnabled = false;
            searchTextBox.IsEnabled = false;

            string searchTerm = searchTextBox.Text;
            string searchConstraint = ((ComboBoxItem)searchComboBox.SelectedItem).Name;

            IEnumerable<EcofOApplicationObject> searchList;
            List<EcofOApplicationObject> currentList;
            ListView currentListView;
            TabItem currentTab = (TabItem)TabControl.SelectedItem;
            //bool isReprint = false;

            if (DefaultTab.Equals(currentTab))
            {
                currentList = m_AssignmentList;
                currentListView = itemListView;
            }
            else
            {
                currentList = m_ReprintList;
                currentListView = reprintItemListView;
            }

            switch (searchConstraint)
            {
                case "holderNameAddress":
                    searchList = currentList.Where(
                        appli => ((appli.application.Holder.City != null && appli.application.Holder.City.IndexOf(
                            searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
                            (appli.application.Holder.ContactAddress != null && appli.application.Holder.ContactAddress.IndexOf(
                                searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
                                (appli.application.Holder.ContactAddressLga != null && appli.application.Holder.ContactAddressLga.IndexOf(
                                    searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
                                    (appli.application.Holder.ContactAddressState != null &&
                                    appli.application.Holder.ContactAddressState.IndexOf(
                                        searchTerm, StringComparison.OrdinalIgnoreCase) >= 0)));
                    break;
                case "propertyAddress":
                    searchList = currentList.Where(
                        appli => ((appli.application.PropertyLga != null && appli.application.PropertyLga.IndexOf(
                            searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
                            (appli.application.PropertyLocation != null && appli.application.PropertyLocation.IndexOf(
                                searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
                                (appli.application.PropertyLocationDescription != null && appli.application.PropertyLocationDescription.IndexOf(
                                    searchTerm, StringComparison.OrdinalIgnoreCase) >= 0)));
                    break;
                case "propertyUse":
                    searchList = currentList.Where(
                        appli => (appli.ApprovedTypeOfUse != null &&
                            appli.ApprovedTypeOfUse.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
                case "trackCode":
                    // This cannot be null. We check all the same
                    searchList = currentList.Where(
                        appli => (appli.TrackCode != null &&
                            appli.application.TrackCode.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
                case "scheme":
                    searchList = currentList.Where(
                        appli => (appli.Scheme != null &&
                            appli.Scheme.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
                case "surveyPlanNum":
                    searchList = currentList.Where(
                        appli => (appli.application.SurveyPlanNo != null &&
                            appli.application.SurveyPlanNo.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
                case "coordinateOne":
                    searchList = currentList.Where(
                        appli => (appli.application.PropertyCordinate1 != null &&
                            appli.application.PropertyCordinate1.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
                case "coordinateTwo":
                    searchList = currentList.Where(
                        appli => (appli.application.PropertyCordinate2 != null &&
                            appli.application.PropertyCordinate2.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
                case "holderName":
                default:
                    searchList = currentList.Where(
                        appli => (appli.application.Holdernames != null &&
                            appli.application.Holdernames.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
                    break;
            }

            currentListView.Items.Clear();
            foreach (EcofOApplicationObject app in searchList)
            {
                currentListView.Items.Add(app);
            }
            refreshDisplay();

            searchButton.IsEnabled = true;
            searchTextBox.IsEnabled = true;
        }

I have read other suggestions about this same issue, but none seems to work for me. How do I solve this issue?

user8107351
  • 367
  • 4
  • 20
  • 1
    You cannot modify a collection that you are iterating using a `foreach`. Use separate collections or a `for` loop. – mm8 Sep 25 '19 at 13:57
  • 1
    As a note, you might want to look at the [async/await programming model](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/) in order to avoid constructs like starting a Thread from a Thread. You would declare your fetchThumbnailsAsync method async and call `await fetchThumbnailsAsync(obj);` – Clemens Sep 25 '19 at 14:23
  • @xdtTransform, I tried the solutions in that post, and it did not work for me, There is no ToList() for ItemCollection – user8107351 Sep 25 '19 at 14:38
  • @nm8 Your solution worked for me!...After changing the iteration to a for loop, it now works perfectly! Thanks!!!. – user8107351 Sep 26 '19 at 07:37

1 Answers1

0

You can create a copy of the items like this:

var itemsCopy = assignmentPage.reprintItemListView.Items.Cast<object>().ToArray();

It is still not safe though to create this copy in a different thread than the UI thread. You may still get some rare Collection was modified... exceptions. To make it 100% safe you must create the copy while still running in the UI thread. To pass the copy in the newAppsThread you could use a ParameterizedThreadStart:

var reprintAppsThread = new Thread(itemsCopy =>

//...

reprintAppsThread.Start(
    assignmentPage.reprintItemListView.Items.Cast<object>().ToArray());
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104