2013-08-28

I struggled for a couple of hours on this one... until finally finding this useful answer from stackoverflow.com! My scenario was needing to copy some files in a pre-build step in a Visual Studio C# project. For every file I needed to copy, there was a counterpart for each of our supported languages. The naming convention for the files was like this:

After attempting multiple combinations of wildcard patterns and having no success, I changed the search phrases I used to search the internet and found the stackoverflow thread.
The most important part from the thread, and the most important thing to remember about using Include and Exclude is:

If you use an absolute path for Include, you must use an absolute path for Exclude. If you use a relative path for Include, you must use a relative path for both.

2013-08-09

The ObservableCollection<T>.CollectionChanged event will only fire if the collection itself changes (items are added, removed or rearranged/moved.), NOT if an item in the collection changes (meaning one of the item's in the collection has one or more properties modified.)

It's now around 2:30am, and I've been going the rounds for a couple of hours with a Silverlight project at work; fighting a seemingly simple change that ended up not being so simple because of a major misunderstanding of the CollectionChanged event on the ObservableCollection<T>. My ObservableCollection<T>.CollectionChanged event was not firing like I thought it should.

I imagine this will be a common mistake for others, and I'm sure I myself am doomed to repeat it again in the future; so I'm documenting it for a quick reminder later.

My thought process was this... "I need to watch my ObservableCollection for one of its items to be changed. Once the item is changed, I need to flip a boolean flag which happens to be bound to a command which will disable a button after the change has been made."

Simple, right?
I should just be able to handle the ObservableCollection<T>.CollectionChanged event, because if one of those items in the collection gets changed, that counts...

Or not.

See, the misconception is, the collection itself hasn't changed. It has the exact same items it had before, it's just that the item within the collection changed. So there are two things that can happen to your collection:

The collection itself is modified (Items are added, removed or moved.)

An item in the collection is modified (its individual properties are changed.)

Let me illustrate:
For this example we will have a class called VideoGame to keep track of titles and costs.

ObservableCollection<VideoGame> videoGames = new ObservableCollection<VideoGame>
{
new VideoGame{ Title = "TrackMania 2: Stadium", Cost = 9.99M },
new VideoGame{ Title = "TrackMania 2: Canyon", Cost = 19.99M },
new VideoGame{ Title = "TrackMania 2: Valley", Cost = 19.99M },
};
videoGames.CollectionChanged += (sender, eventArgs) => {
Debug.WriteLine("--- The collection changed");
};
Debug.WriteLine("Changing the cost of one of the video games in the collection...");
// The CollectionChanged event will not fire because it was just one of the collection's items that changed...
// not the collection itself.
videoGames[0].Cost = 7.99M; // the game went on sale.
Debug.WriteLine("Adding a video game to the collection...");
// The CollectionChanged event WILL fire because the collection of items changed.
videoGames.Add(new VideoGame{ Title ="ShootMania: Storm", Cost = 19.99M });

And the output...

Changing the cost of one of the video games in the collection...Adding a video game to the collection...--- The collection changed

When it dawned on me, at first I was frustrated; but then clarity set in. It makes sense to me that we only want the CollectionChanged event to fire when the collection itself is modified, not its individual parts. With it, the NotifyCollectionChangedEventArgs that are passed with the event give us a lot of good information about what happened with the change.

While all this is cool, what do I need to have happen so I can track when an item in the collection is changed?

I need to make sure I handle PropertyChanged on the individual items of the collection. Make note, this can be tricky because I still need to watch for the Collection to change so I can subscribe to any new items' PropertyChanged events as they are added to the collection, and clean up after myself when the items leave the collection.

I'll let you decide how you're going to approach that; it's a discussion for another day. But I want to drive home the concept that the CollectionChanged event is just that... when the collection itself changes, not its individual items. Know that, and you'll save yourself a lot of time.