2010-12-06 38 views
21

J'ai une propriété attachée de type ObservableCollection sur un contrôle. Si j'ajoute ou supprime des éléments de la collection, l'interface utilisateur ne se met pas à jour. Toutefois, si je remplace la collection par une nouvelle, le ViewModel est mis à jour par l'interface utilisateur. Est-ce que quelqu'un peut me donner un exemple de ce que j'ai besoin de faire dans l'objet de dépendance pour qu'il puisse gérer les changements au sein de la collection?La propriété de dépendance ObservableCollection ne se met pas à jour lorsque l'élément de collection est supprimé

Une partie de l'objet de dépendance est ci-dessous:

public class RadCalendarBehavior : DependencyObject 
{ 
private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var calendar = d as RadCalendar; 
    if (e.NewValue != null) 
    { 
    calendar.DayTemplateSelector = new SpecialDaySelector((ObservableCollection<DateTime>)e.NewValue, GetSpecialDayTemplate(d)); 
    } 
} 

public static ObservableCollection<DateTime> GetSpecialDays(DependencyObject obj) 
{ 
    return (ObservableCollection<DateTime>)obj.GetValue(SpecialDaysProperty); 
} 

public static void SetSpecialDays(DependencyObject obj, ObservableCollection<DateTime> value) 
{ 
    obj.SetValue(SpecialDaysProperty, value); 
} 

public static readonly DependencyProperty SpecialDaysProperty = 
    DependencyProperty.RegisterAttached("SpecialDays", typeof(ObservableCollection<DateTime>), typeof(RadCalendarBehavior), new UIPropertyMetadata(null, OnSpecialDaysChanged)); 
} 
} 

Je comprends que je dois enregistrer que la collection a changé, mais je ne suis pas sûr comment faire cela dans la propriété de dépendance

Répondre

33

A modification au sein de la collection ne déclenchera pas le rappel OnSpecialDaysChanged, car la valeur de la propriété de dépendance n'a pas changé. Si vous avez besoin de réagir pour détecter les changements avec la collection, vous devez gérer l'événement événement CollectionChanged manuellement:

private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var calendar = d as RadCalendar; 

    if (e.OldValue != null) 
    { 
    var coll = (INotifyCollectionChanged)e.OldValue; 
    // Unsubscribe from CollectionChanged on the old collection 
    coll.CollectionChanged -= SpecialDays_CollectionChanged; 
    } 

    if (e.NewValue != null) 
    { 
    var coll = (ObservableCollection<DateTime>)e.NewValue; 
    calendar.DayTemplateSelector = new SpecialDaySelector(coll, GetSpecialDayTemplate(d)); 
    // Subscribe to CollectionChanged on the new collection 
    coll.CollectionChanged += SpecialDays_CollectionChanged; 
    } 
} 

private static void SpecialDays_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    // handle CollectionChanged 
} 
+0

Merci. Est-il possible d'obtenir une référence de l'objet de dépendance dans SpecialDays_CollectionChanged? – GoalMaker

+0

Quel objet de dépendance? Vous voulez dire le RadCalendar? Pas facilement ... de toute façon, je ne suis pas sûr que ça aurait du sens: et si plusieurs instances de RadCalendar sont liées à la même collection? –

+0

Je vois ce que tu veux dire. J'essayais de faire en sorte que RadCalendar ne mette plus en évidence un jour spécial s'il était retiré de la collection, alors j'ai pensé que je pourrais le faire en créant un SpecialDaySelector et en définissant le DayTemplateSelector du contrôle Calendar. – GoalMaker

5

Ceci est juste d'ajouter à la réponse de Thomas. Dans mon code, je n'Interagir avec les propriétés de DependencyObject en créant un objet gestionnaire localy comme ci-dessous:

private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var action = new NotifyCollectionChangedEventHandler(
      (o, args) => 
       { 
        var calendar = d as RadCalendar; 

        if (calendar!= null) 
        { 
         // play with calendar's properties/methods 
        } 
       }); 

    if (e.OldValue != null) 
    { 
     var coll = (INotifyCollectionChanged)e.OldValue; 
     // Unsubscribe from CollectionChanged on the old collection 
     coll.CollectionChanged -= action; 
    } 

    if (e.NewValue != null) 
    { 
     var coll = (ObservableCollection<DateTime>)e.NewValue; 
     // Subscribe to CollectionChanged on the new collection 
     coll.CollectionChanged += action; 
    } 
} 

Espérons que cela est utile à quelqu'un.

+0

Ceci est utile oui, je cherche un moyen d'accéder à DependencyObject dans le CollectionChangedEventHandler, et cela semble fonctionner. J'ai du mal à croire que c'est la seule façon de faire ... Faisons-nous quelque chose de mal? J'ai un DP ObservableCollection, quand des éléments y sont ajoutés (événement collectionchanged est déclenché ...), j'ai besoin de faire des trucs au contrôle principal (comme ajouter des sous-contrôles). Et votre solution est la seule que j'ai trouvée pour accéder à DependencyObj. Depuis ce post avez-vous trouvé un autre moyen? – Sam

2

Si vous avez une propriété de dépendance de type de collecte garder les points suivants à l'esprit:

Si votre propriété est un type de référence, la valeur par défaut spécifiée dans les métadonnées de propriété de dépendance ne sont pas une valeur par défaut par exemple; à la place, c'est une valeur par défaut qui s'applique à toutes les instances du type. [...]
Pour corriger ce problème, vous devez réinitialiser la valeur de la propriété de dépendance de collection à une instance unique, dans le cadre de l'appel du constructeur de classe.

(voir MSDN Collection-Type Dependency Properties)

Pour répondre à Sam question (je viens de rencontrer le même problème):

Faites votre CollectionChanged-gestionnaire non-statique et vous désabonner/réabonner sur instance- niveau.

private static void OnSpecialDaysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var calendar = d as RadCalendar; 

    if (e.OldValue != null) 
    { 
    var coll = (INotifyCollectionChanged)e.OldValue; 
    // Unsubscribe from CollectionChanged on the old collection of the DP-instance (!) 
    coll.CollectionChanged -= d.SpecialDays_CollectionChanged; 
    } 

    if (e.NewValue != null) 
    { 
    var coll = (ObservableCollection<DateTime>)e.NewValue; 
    calendar.DayTemplateSelector = new SpecialDaySelector(coll, GetSpecialDayTemplate(d)); 
    // Subscribe to CollectionChanged on the new collection of the DP-instance (!) 
    coll.CollectionChanged += d.SpecialDays_CollectionChanged; 
    } 
} 

private void SpecialDays_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    // handle CollectionChanged on instance-level 
}