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