Ошибка: этот тип CollectionView не поддерживает изменения в SourceCollection.

У меня есть ObservableCollection элементов, которые мне нужно обновить и представить данные с помощью ICollectionView.

Вот соответствующие фрагменты кода:

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

Вот CollectionView и его фильтр:

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

Я получаю следующую ошибку в следующем фрагменте кода:

В PresentationFramework.dll возникло необработанное исключение типа «System.NotSupportedException».

Дополнительная информация. Этот тип CollectionView не поддерживает изменения своей SourceCollection из потока, отличного от потока Dispatcher.

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

Ошибка возникает, когда у меня есть строка HeroesDB.Add(...) сразу после попытки поймать.

Я пробовал массу вещей, ни одна из которых не сработала.

Я попытался использовать другой ObservableCollection в качестве отфильтрованного списка и отфильтровать его, но все равно выдает ошибку. Я пытался использовать MTObservableCollection и AsyncObservableCollection, взятые с первой страницы Google, которую опубликовали другие, но они также путаются и в других отношениях.

Как бы мне справиться с этим? Мне нужно иметь возможность фильтровать, мне нужна их коллекция, и когда источник меняется, мне нужно сразу же видеть эти изменения в приложении.


person pingu2k4    schedule 19.11.2015    source источник
comment
ваша команда HeroesDBAddEntry вызывается потоком без графического интерфейса?   -  person GazTheDestroyer    schedule 19.11.2015
comment
Вызывается при нажатии кнопки. Команда кнопки привязана к нему.   -  person pingu2k4    schedule 19.11.2015
comment
Я не хочу быть сердечным, но я рекомендую вам прочитать эту книгу. amazon.com/Clean-Code-Handbook-Software-Craftsmanship/ дп/   -  person Hossein Shahdoost    schedule 19.11.2015
comment
Обязательно не используйте конкатенацию строк для SQL-запросов, потому что вы подвергаете себя SQL-инъекциям.   -  person Mike Eason    schedule 20.11.2015


Ответы (1)


Вы пытались обернуть весь свой код, который настраивает фильтр, на вызов диспетчера WPF?

Как правило, это необходимо сделать, если коллекция, привязанная к представлению, изменяется в коде потока, отличного от потока пользовательского интерфейса.

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => { 
    HeroesDBAddHeroes();
  }));
person Martin    schedule 23.11.2015
comment
Пробовали диспетчер несколькими способами, но всегда появлялись ошибки. Я поставил код ошибки в диспетчере, как вы дали, ошибка была: 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. - person pingu2k4; 23.11.2015
comment
Странный. Я помню, что однажды у меня была ошибка, подобная вашей, при настройке фильтра CollectionViewSource. Перемещение этого кода в диспетчер исправило это для меня. - person Martin; 23.11.2015
comment
В какой строке вашего кода вы получаете исключение? - person Martin; 23.11.2015
comment
HeroesDBHeroes.Add(new Hero( - сразу после попытки поймать в последнем блоке кода в OP - person pingu2k4; 23.11.2015
comment
Извините, это уже было объяснено в вашем вопросе. Итак, теперь у вас есть диспетчер вокруг кода в моем ответе (вызов вашего метода HeroesDBAddHeroes();), а также вокруг этой строки: HeroesDBHeroes.Add(new Hero(...? - person Martin; 23.11.2015
comment
Хорошо, я пропустил случай, когда я вызывал HeroesDBAddHeroes(). Я делаю это сейчас и, кажется, работает... Могу ли я проверить, должен ли я запускать его через диспетчер КАЖДЫЙ раз, когда я хочу что-то сделать с ObservableColletion? - person pingu2k4; 23.11.2015
comment
Давайте продолжим обсуждение в чате. - person Martin; 23.11.2015