Error: This type of CollectionView does not support changes to its SourceCollection

pingu2k4 picture pingu2k4 · Nov 19, 2015 · Viewed 9k times · Source

I have an ObservableCollection of items, which I need to be able to update and have the data represented still using an ICollectionView.

Here are relevant bits of code:

private ObservableCollection<Hero> heroesDBHeroes;
public ObservableCollection<Hero> HeroesDBHeroes
{
    get
    {
        return heroesDBHeroes;
    }
    set
    {
        heroesDBHeroes = value;
        OnPropertyChanged("HeroesDBHeroes");
    }
}
private void HeroesDBAddHeroes()
{
    if(HeroesDBHeroes != null)
    {
        HeroesDBHeroes.Clear();
    }
    HeroesDBHeroes = Hero.GetAllHeroes();

    HeroesDBFilteredHeroes = new ListCollectionView(HeroesDBHeroes);
    HeroesDBFilteredHeroes.Filter = new Predicate<object>(HeroesDBFilterHeroes);
    HeroesDBFilteredHeroes.Refresh();
    OnPropertyChanged("HeroesDBFilteredHeroes");
}

Here is the CollectionView and its filter:

    public CollectionView HeroesDBFilteredHeroes { get; set; }
    public bool HeroesDBFilterHeroes(object item)
    {
        Hero h = item as Hero;
        bool ID, Name, GoldMinimum, GoldMaximum, PlatinumMinimum, PlatinumMaximum, DBTag, ReleaseDateStart, ReleaseDateEnd, Available, Sale, Featured, New, F2P, Homepage, Thumbnail, FeaturedThumbnail, ShortDescription, Description;

        ID = Name = GoldMinimum = GoldMaximum = PlatinumMinimum = PlatinumMaximum = DBTag = ReleaseDateStart = ReleaseDateEnd = Available = Sale = Featured = New = F2P = Homepage = Thumbnail = FeaturedThumbnail = ShortDescription = Description = false;

        if (h == null)
        {
            return false;
        }

        if (HeroesDBFilterID == null || HeroesDBFilterID == h.ID)
        {
            ID = true;
        }

        if (HeroesDBFilterName == "" || h.Name.IndexOf(HeroesDBFilterName, 0, StringComparison.CurrentCultureIgnoreCase) != -1)
        {
            Name = true;
        }

        if (HeroesDBFilterGoldMinimum == null || HeroesDBFilterGoldMinimum <= h.Gold)
        {
            GoldMinimum = true;
        }

        if (HeroesDBFilterGoldMaximum == null || HeroesDBFilterGoldMaximum >= h.Gold)
        {
            GoldMaximum = true;
        }

        if (HeroesDBFilterPlatinumMinimum == null || HeroesDBFilterPlatinumMinimum <= h.Platinum)
        {
            PlatinumMinimum = true;
        }

        if (HeroesDBFilterPlatinumMaximum == null || HeroesDBFilterPlatinumMaximum >= h.Platinum)
        {
            PlatinumMaximum = true;
        }

        if (HeroesDBFilterDBTag == "" || h.DBTag.IndexOf(HeroesDBFilterDBTag, 0, StringComparison.CurrentCultureIgnoreCase) != -1)
        {
            DBTag = true;
        }

        if (HeroesDBFilterReleaseDateStart == null || HeroesDBFilterReleaseDateStart <= h.ReleaseDate)
        {
            ReleaseDateStart = true;
        }

        if (HeroesDBFilterReleaseDateEnd == null || HeroesDBFilterReleaseDateEnd >= h.ReleaseDate)
        {
            ReleaseDateEnd = true;
        }

        switch(HeroesDBFilterAvailable)
        {
            case 0:
                Available = true;
                break;
            case 1:
                if(h.Available == true)
                {
                    Available = true;
                }
                break;
            case 2:
                if (h.Available == false)
                {
                    Available = true;
                }
                break;
        }

        switch (HeroesDBFilterSale)
        {
            case 0:
                Sale = true;
                break;
            case 1:
                if (h.Sale == true)
                {
                    Sale = true;
                }
                break;
            case 2:
                if (h.Sale == false)
                {
                    Sale = true;
                }
                break;
        }

        switch (HeroesDBFilterFeatured)
        {
            case 0:
                Featured = true;
                break;
            case 1:
                if (h.Featured == true)
                {
                    Featured = true;
                }
                break;
            case 2:
                if (h.Featured == false)
                {
                    Featured = true;
                }
                break;
        }

        switch (HeroesDBFilterNew)
        {
            case 0:
                New = true;
                break;
            case 1:
                if (h.NewTag == true)
                {
                    New = true;
                }
                break;
            case 2:
                if (h.NewTag == false)
                {
                    New = true;
                }
                break;
        }

        switch (HeroesDBFilterF2P)
        {
            case 0:
                F2P = true;
                break;
            case 1:
                if (h.F2P == true)
                {
                    F2P = true;
                }
                break;
            case 2:
                if (h.F2P == false)
                {
                    F2P = true;
                }
                break;
        }

        switch (HeroesDBFilterHomepage)
        {
            case 0:
                Homepage = true;
                break;
            case 1:
                if (h.Homepage == true)
                {
                    Homepage = true;
                }
                break;
            case 2:
                if (h.Homepage == false)
                {
                    Homepage = true;
                }
                break;
        }

        switch (HeroesDBFilterThumbnail)
        {
            case 0:
                Thumbnail = true;
                break;
            case 1:
                if (h.ThumbnailImage.Count<byte>() >= 5)
                {
                    Thumbnail = true;
                }
                break;
            case 2:
                if (h.ThumbnailImage.Count<byte>() < 5)
                {
                    Thumbnail = true;
                }
                break;
        }

        switch (HeroesDBFilterFeaturedThumbnail)
        {
            case 0:
                FeaturedThumbnail = true;
                break;
            case 1:
                if (h.FeaturedThumbnailImage.Count<byte>() >= 5)
                {
                    FeaturedThumbnail = true;
                }
                break;
            case 2:
                if (h.FeaturedThumbnailImage.Count<byte>() < 5)
                {
                    FeaturedThumbnail = true;
                }
                break;
        }

        if (HeroesDBFilterShortDescription == "" || h.ShortDescription.IndexOf(HeroesDBFilterShortDescription, 0, StringComparison.CurrentCultureIgnoreCase) != -1)
        {
            ShortDescription = true;
        }

        if (HeroesDBFilterDescription == "" || h.Description.IndexOf(HeroesDBFilterDescription, 0, StringComparison.CurrentCultureIgnoreCase) != -1)
        {
            Description = true;
        }

        return ID && Name && GoldMinimum && GoldMaximum && PlatinumMinimum && PlatinumMaximum && DBTag && ReleaseDateStart && ReleaseDateEnd && Available && Sale && Featured && New && F2P && Homepage && Thumbnail && FeaturedThumbnail && ShortDescription && Description;
    }

I get the following error in the following code snippet:

An unhandled exception of type 'System.NotSupportedException' occurred in PresentationFramework.dll

Additional information: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

private ICommand heroesDBAddEntry;
public ICommand HeroesDBAddEntry
{
    get
    {
        if (heroesDBAddEntry == null)
        {
            heroesDBAddEntry = new RelayCommand(HeroesDBAddEntryEx, null);
        }
        return heroesDBAddEntry;
    }
}
private void HeroesDBAddEntryEx(object p)
{
    if (HeroesDBUpdateID != null)
    {
        HeroesDBUpdateEntryEx();
        return;
    }

    int x;
    var db = new SQLiteDatabase();

    string query, changesQuery;

    query = "INSERT INTO Heroes (Name,Description,ShortDescription,Gold,Platinum,DBTag,ReleaseDate,Available,Sale,Featured,NewTag,F2P,Homepage,ThumbnailImage,ThumbnailImageName," +
        "FeaturedThumbnailImage,FeaturedThumbnailImageName) ";

    query += "VALUES ('" + HeroesDBName.Replace("'", "''") + "','" + HeroesDBDescription.Replace("'", "''") + "','" + HeroesDBShortDescription.Replace("'", "''") + "'," +
        HeroesDBGold + "," + HeroesDBPlatinum + ",'" + HeroesDBDBTag.Replace("'", "''") + "','" + HeroesDBReleaseDate.Date.ToString("yyyy-MM-dd") + "'," +
        Convert.ToInt32(HeroesDBAvailable) + "," + Convert.ToInt32(HeroesDBSale) + "," + Convert.ToInt32(HeroesDBFeatured) + "," + Convert.ToInt32(HeroesDBNewTag) + "," +
        Convert.ToInt32(HeroesDBF2P) + "," + Convert.ToInt32(HeroesDBHomepage) + ",'" + Convert.ToBase64String(HeroesDBThumbnailImage) + "','" +
        HeroesDBThumbnailPath.Replace("'", "''") + "','" + Convert.ToBase64String(HeroesDBFeaturedThumbnailImage) + "','" + HeroesDBFeaturedThumbnailPath.Replace("'", "''") + "'); ";

    changesQuery = "INSERT INTO Heroes_Changes (HeroID,Action,TimeStamp,User,Name,Description,ShortDescription,Gold,Platinum,DBTag,ReleaseDate,Available,Sale,Featured,NewTag,F2P," +
        "Homepage,ThumbnailImage,ThumbnailImageName,FeaturedThumbnailImage,FeaturedThumbnailImageName) ";

    changesQuery += "VALUES (" + HeroesDBNextID + ",'" + "INSERT" + "','" + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + "','" + Environment.UserName + "','" +
        HeroesDBName.Replace("'", "''") + "','" + HeroesDBDescription.Replace("'", "''") + "','" + HeroesDBShortDescription.Replace("'", "''") + "'," +
        HeroesDBGold + "," + HeroesDBPlatinum + ",'" + HeroesDBDBTag.Replace("'", "''") + "','" + HeroesDBReleaseDate.Date.ToString("yyyy-MM-dd") + "'," +
        Convert.ToInt32(HeroesDBAvailable) + "," + Convert.ToInt32(HeroesDBSale) + "," + Convert.ToInt32(HeroesDBFeatured) + "," + Convert.ToInt32(HeroesDBNewTag) + "," +
        Convert.ToInt32(HeroesDBF2P) + "," + Convert.ToInt32(HeroesDBHomepage) + ",'" + Convert.ToBase64String(HeroesDBThumbnailImage) + "','" +
        HeroesDBThumbnailPath.Replace("'", "''") + "','" + Convert.ToBase64String(HeroesDBFeaturedThumbnailImage) + "','" + HeroesDBFeaturedThumbnailPath.Replace("'", "''") + "'); ";

    try
    {
        x = db.ExecuteNonQuery(query);
        HeroesDBStatus = x + " Record(s) Added.";
        x = db.ExecuteNonQuery(changesQuery);
    }
    catch(Exception err)
    {
        System.Windows.Forms.MessageBox.Show(err.Message);
    }

    HeroesDBHeroes.Add(new Hero(
        HID: HeroesDBNextID,
        HName: HeroesDBName,
        HDescription: HeroesDBDescription,
        HShortDescription: HeroesDBShortDescription,
        HGold: HeroesDBGold,
        HPlatinum: HeroesDBPlatinum,
        HDBTag: HeroesDBDBTag,
        HReleaseDate: HeroesDBReleaseDate,
        HAvailable: HeroesDBAvailable,
        HSale: HeroesDBSale,
        HFeatured: HeroesDBFeatured,
        HNewTag: HeroesDBNewTag,
        HF2P: HeroesDBF2P,
        HHomepage: HeroesDBHomepage,
        HThumbnailImage: HeroesDBThumbnailImage,
        HThumbnailImageName: HeroesDBThumbnailPath,
        HFeaturedThumbnailImage: HeroesDBFeaturedThumbnailImage,
        HFeaturedThumbnailImageName: HeroesDBFeaturedThumbnailPath,
        HForce: true
        ));
    HeroesDBNextID++;

    HeroesDBName = "";
    HeroesDBDescription = "";
    HeroesDBShortDescription = "";
    HeroesDBGold = 0;
    HeroesDBPlatinum = 0;
    HeroesDBDBTag = "";
    HeroesDBReleaseDate = DateTime.Today;
    HeroesDBAvailable = false;
    HeroesDBSale = false;
    HeroesDBFeatured = false;
    HeroesDBNewTag = false;
    HeroesDBF2P = false;
    HeroesDBHomepage = false;
    HeroesDBThumbnailImage = new byte[] { 0x00 };
    HeroesDBThumbnailPath = "";
    HeroesDBFeaturedThumbnailImage = new byte[] { 0x00 };
    HeroesDBFeaturedThumbnailPath = "";
    HeroesDBUpdateID = null;
}

The error happens where I have the HeroesDB.Add(...) line, just after the try catch.

I have tried a ton of things, none of which have worked.

I have tried using another ObservableCollection as the filtered list and filtering that, but it still gives me an error. I have tried using MTObservableCollection and AsyncObservableCollection taken from the first page of google which others have posted, but they mess up in other ways as well.

How would I go about tackling this one? I need to be able to filter, I need a collection of them, and when the source changes I need to see those changes in the app right away.

Answer

Martin picture Martin · Nov 23, 2015

Have you tried wrapping all your code which sets up the filter to a call to the WPF dispatcher?

Generally this has to be done if the collection bound to the view is modified in code of a thread different than the UI thread.

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => { 
    HeroesDBAddHeroes();
  }));