Basically you need to decide if users of the class are likely to be confused by the fact that they can't, for example, do:
for(int i=0; i=< myCollection.Count; i++)
{
... myCollection[i] ...
}
though they can of course use foreach, or use a cast:
for(int i=0; i=< myCollection.Count; i++)
{
... ((Collection<MyType>)myCollection)[i] ...
}
It's not an easy decision, as it can easily lead to eisenbugs. I decided to allow it in one of my apps, where access from users of the class was almost exclusively by key.
I'm not sure I'd do so for a shared class library though: in general I'd avoid exposing a KeyedCollection in a public API: instead I would expose IList<T> in a public API, and consumers of the API who need keyed access can define their own internal KeyedCollection with a constructor that takes an IEnumerable<TItem> and populates the collection with it. This means you can easily build a new KeyedCollection from a list retrieved from an API.
Regarding serialization, there is also a performance problem that I reported to Microsoft Connect: the KeyedCollection maintains an internal dictionary as well as a list, and serializes both - it is sufficient to serialize the list as the dictionary can easily be recreated on deserialization.
For this reason as well as the XmlSerialization bug, I'd recommend you avoid serializing a KeyedCollection - instead only serialize the KeyedCollection.Items list.
I don't like the suggestion of wrapping your int key in another type. It seems to me wrong to add complexity simply so that a type can be used as an item in a KeyedCollection. I'd use a string key (ToString) rather than doing this - this is rather like the VB6 Collection class.
FWIW, I asked the same question some time ago on the MSDN forums. There is a response from a member of the FxCop team, but no conclusive guidelines.