RoutedEvents gehören zum Visual- bzw. LogicalTree. Eventuell könnte man 
da was machen, wenn man ein CustomControl selbst implementiert und die 
Route für das eigene Event bestimmt. Damit kenne ich mich nicht aus und 
vermutlich wäre die Lösung alles andere als optimal.
Wenn du UIElements in einer ObservableCollection(T) hast, läuft mit 
Sicherheit was falsch. View und ViewModel sollten getrennt werden 
(natürlich auch das Model - wo die Grenzen liegen, hängt von der 
Anwendung ab). Dann hat man im ViewModel die View-repräsentierenden 
Objekte, die INotifyPropertyChanged bzw. INotifyCollectionChanged 
implementieren und die man per DataBinding an entsprechende in XAML 
definierte View-Elemente bindet. Dabei helfen DataTemplates in 
ItemsControls, die bestimmen, wie Items einer Collection dargestellt 
werden.
Bleibt aber das Problem, dass man nicht mitbekommt, wenn sich ein Item 
in der Collection ändert (wenn man das Problem im ViewModel lösen 
möchte). Als Alternative bliebe die alte BindingList(T), deren 
ListChanged-Event auch ausgelöst wird, wenn ein Item das 
INotifyPropertyChanged.PropertyChanged feuert. Leider sind in den 
EventArgs nur der alte und neue Index des geänderten Items hinterlegt, 
was bei einem Remove problematisch ist - was soll man mit dem Index für 
ein Item, das nicht mehr da ist? Ausserdem gibt es die BindingList(T) 
nicht in Silverlight.
Wenn es wirklich notwendig ist, auf Änderungen der Items-Objekte zu 
reagieren, würde ich wohl die ObservableCollection(T) in etwa wie folgt 
erweitern:
1  | public class EnhancedCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
  | 
2  | {
 | 
3  |     public event EventHandler<ItemChangedEventArgs<T>> ItemChanged;
  | 
4  |     public EnhancedCollection()
  | 
5  |     {
 | 
6  |         CollectionChanged += (s, e) =>
  | 
7  |         {
 | 
8  |             if (e.OldItems != null) foreach (INotifyPropertyChanged oldItem in e.OldItems) oldItem.PropertyChanged -= item_PropertyChanged;
  | 
9  |             if (e.NewItems != null) foreach (INotifyPropertyChanged newItem in e.NewItems) newItem.PropertyChanged += item_PropertyChanged;
  | 
10  |         };
  | 
11  |     }
  | 
12  |     private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
  | 
13  |     {
 | 
14  |         if (ItemChanged != null) ItemChanged(this, new ItemChangedEventArgs<T>((T)sender, e.PropertyName));
  | 
15  |     }
  | 
16  | }
  | 
17  | 
  | 
18  | public class ItemChangedEventArgs<T> : EventArgs
  | 
19  | {
 | 
20  |     public T Item { get; private set; }
 | 
21  |     public string PropertyName { get; private set; }
 | 
22  | 
  | 
23  |     public ItemChangedEventArgs(T item, string propertyName)
  | 
24  |     {
 | 
25  |         Item = item;
  | 
26  |         PropertyName = propertyName;
  | 
27  |     }
  | 
28  | }
  | 
So kann man in der Klasse, die ein Objekt der EnhancedCollection(T) 
referenziert auf die CollectionChanged- und ItemChanged-Events reagieren 
und eventuell auch noch "weiter hinauf" (Im Objektmodell hat man anders 
als in den WPF-Trees nicht zwingend eine Baustruktur!) triggern. In den 
ItemChangedEventArgs hat man dann die Item-Referenz und den Namen des 
Propertys, das sich geändert hat.
Wenn man das Ganze nur einmal braucht, könnte man sich die Ableitung 
auch sparen und die Logik in die Klasse bauen, die ein Objekt der 
ObservableCollection(T) referenziert.
Ein anderer Ansatz wäre, dem Datenobjekt im Konstruktor das Objekt 
mitzugeben, das letztlich auf die Änderungen reagieren soll. Dann 
bräuchte man die Collections gar nicht anfassen. :)