错误:此类型的CollectionView不支持对其SourceCollection的更改。

4
我有一个项的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;
    }

在以下代码片段中,我遇到了以下错误:

未处理的异常类型 'System.NotSupportedException' 发生在 PresentationFramework.dll 中

附加信息:此类型的 CollectionView 不支持从与 Dispatcher 线程不同的线程更改其 SourceCollection。

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

错误发生在try catch之后的HeroesDB.Add(...)行。
我已经尝试了很多方法,但都没有起作用。
我尝试使用另一个ObservableCollection作为过滤列表并进行过滤,但仍然出现错误。我尝试使用从谷歌首页获取的MTObservableCollection和AsyncObservableCollection,但它们也会出现其他问题。
我该如何解决这个问题?我需要能够进行过滤,我需要一个集合,并且当源更改时,我需要立即在应用程序中看到这些更改。

你的 HeroesDBAddEntry 命令是否被非 GUI 线程调用? - GazTheDestroyer
在按钮按下时被调用。按钮命令与其绑定。 - pingu2k4
我不是有意冒犯,但我建议你阅读这本书。http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882 - Hossein Shahdoost
2
必须遵循“不要在 SQL 查询中使用字符串连接,因为这会让你面临 SQL 注入”的原则。 - Mike Eason
1个回答

23

您尝试过将所有设置筛选器的代码包装到调用WPF调度程序的函数中吗?

通常,如果绑定到视图的集合在不同于UI线程的线程的代码中被修改,则必须执行此操作。

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

尝试了多种方式使用Dispatcher,但仍然遇到错误。我按照你的提示把出错的代码放在了Dispatcher中,但是出现了以下错误:“PresentationFramework.dll中发生了类型为‘System.NotSupportedException’的未处理异常。额外信息:此CollectionView类型不支持在与Dispatcher线程不同的线程中对其SourceCollection进行更改。” - pingu2k4
你的代码在哪一行出现了异常? - Martin
HeroesDBHeroes.Add(new Hero( - 在 OP 代码的最终块中的 try catch 后面。 - pingu2k4
1
抱歉,这已经在你的问题中解释过了。所以现在你需要在我的回答中将调度程序放在你的方法HeroesDBAddHeroes();的代码周围,也要在这一行周围加上调度程序:HeroesDBHeroes.Add(new Hero(... - Martin
好的,我错过了一个调用HeroesDBAddHeroes()的实例。现在我这样做了,似乎可以工作...我可以确认一下,每次我想对ObservableColletion做任何事情,我都必须通过dispatcher吗? - pingu2k4
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接