1

J'ai une classe DependencyObject de base où j'ai une méthode qui prend un objet, obtient les propriétés, et pour chaque propriété qui implémente INotifyPropertyChanged, je ajoutez un nouveau PropertyChangedEventHandler. Maintenant, dans la méthode handler, il obtient les paramètres d'un objet "expéditeur" et le PropertyChangedEventArgs "e". Ma question est, quelqu'un sait-il comment obtenir dynamiquement le nom de la propriété si expéditeur est une propriété d'un type qui implémente le INotifyPropertyChanged.Comment obtenir le nom de propriété de l'objet expéditeur d'un événement INotifyPropertyChanged PropertyChanged

Voici ce que je travaille:

public class BaseDependencyObject : DependencyObject, INotifyPropertyChanged 
{ 
    public BaseDependencyObject() 
    { 

    } 

    protected void SetValues(Object thisObject, Object entity) 
    { 
     try 
     { 
      PropertyInfo[] properties = entity.GetType().GetProperties(); 
      foreach (PropertyInfo property in properties) 
      { 
       var value = property.GetValue(entity, null); 
       var valueIsEntity = value is System.ServiceModel.DomainServices.Client.Entity; 
       var thisObjectsProperty = thisObject.GetType().GetProperty(property.Name); 

       if (thisObjectsProperty != null && value != null) 
       { 
        if (valueIsEntity) 
        { 
         if (thisObjectsProperty.PropertyType.GetInterface("INotifyPropertyChanged", true) != null) 
         { 
          var propertyInstance = Activator.CreateInstance(thisObjectsProperty.PropertyType); 

          ((INotifyPropertyChanged)propertyInstance).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged); 
         } 

         SetValues(thisObjectsProperty, value); 
        } 

        else if (thisObjectsProperty.PropertyType.GetInterface("ICollection", true) != null 
         && thisObjectsProperty.PropertyType.GetGenericArguments().Count() > 0) 
        { 
         Type genericType = thisObjectsProperty.PropertyType.GetGenericArguments()[0]; 

         var observableCollection = Activator.CreateInstance(thisObjectsProperty.PropertyType) as IList; 

         if (observableCollection is INotifyCollectionChanged) 
          ((INotifyCollectionChanged)observableCollection).CollectionChanged += this.Object_CollectionChanged; 

         if (observableCollection is INotifyPropertyChanged) 
          ((INotifyPropertyChanged)observableCollection).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged); 

         foreach (var item in (IEnumerable)value) 
         { 
          var newItem = Activator.CreateInstance(genericType); 

          if (newItem != null) 
          { 
           SetValues(newItem, item); 
           observableCollection.Add(newItem); 
          } 
         } 
        } 

        else 
        { 
         thisObjectsProperty.SetValue(thisObject, value, null); 

        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

    protected void Object_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     switch (e.Action) 
     { 
      case NotifyCollectionChangedAction.Add: 
       foreach (var item in e.NewItems) 
       { 
        if (item is INotifyPropertyChanged) 
        { 
         ((INotifyPropertyChanged)item).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged); 
        } 
       } 
       break; 

      case NotifyCollectionChangedAction.Remove: 
       foreach (var item in e.OldItems) 
       { 
        if (item is INotifyPropertyChanged) 
        { 
         ((INotifyPropertyChanged)item).PropertyChanged -= this.Object_PropertyChanged; 
        } 
       } 
       break; 
     } 

    } 

    protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     this.NotifyPropertyChanged(e.PropertyName); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void NotifyPropertyChanged(string propertyName) 
    { 
     var handler = PropertyChanged; 

     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 

    } 
} 

le premier paramètre de la méthode SetValues ​​est le type DependencyObject qui sera utilisé dans le modèle de vue. Le deuxième paramètre est l'entité qui est renvoyée à partir de Context.LoadOperation du DomainService.

Ce que mon problème se résume à est lorsque le INotifyCollectionChanged.CollectionChanged se déclenche, je dois être en mesure d'élever l'événement PropertyChanged avec le nom de la collection de la propriété. Donc, si quelqu'un a des conseils, je l'apprécierais grandement. Merci d'avance.

Modifier
compris comment obtenir le nom des propriétés qui tire l'événement. Voici une version éditée de mon PropertyChangedEventHandler. Fondamentalement, cela fait ce que je cherchais, mais après tout, je ne fais toujours pas quelque chose de bien. L'UIElement n'est toujours pas mis à jour lors de l'ajout de ObservableCollection qui est une propriété d'un autre type.

Voici un exemple de mes DependencyObjects et ViewModel:

public class LOB : DependencyObject 
{ 
    public Int32 ID 
    { 
     get { return (Int32)GetValue(IDProperty); } 
     set 
     { 
      SetValue(IDProperty, value); 
      NotifyPropertyChanged("ID"); 
     } 
    } 

    public static readonly DependencyProperty IDProperty = 
    DependencyProperty.Register("ID", typeof(Int32), typeof(LOB), null); 

    public ObservableCollection<Group> Groups 
    { 
     get { return (ObservableCollection<Group>)GetValue(GroupsProperty); } 
     set 
     { 
      SetValue(GroupsProperty, value); 
      NotifyPropertyChanged("Groups"); 
     } 
    } 

    public static readonly DependencyProperty GroupsProperty = 
    DependencyProperty.Register("Groups", typeof(ObservableCollection<Group>), typeof(LOB), new PropertyMetadata(null, OnGroupsPropertyChanged)); 

    static void OnGroupsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     if (e.NewValue != null) 
     { 
      ((INotifyCollectionChanged)e.NewValue).CollectionChanged += new NotifyCollectionChangedEventHandler(((LOB)obj).Object_CollectionChanged); 
      ((INotifyPropertyChanged)e.NewValue).PropertyChanged += new PropertyChangedEventHandler(((LOB)obj).Object_PropertyChanged); 
     } 
     if (e.OldValue != null) 
     { 
      ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= ((LOB)obj).Object_CollectionChanged; 
      ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= ((LOB)obj).Object_PropertyChanged; 
     } 
    } 

} 

public class Group : DependencyObject 
{ 
    public Int32 ID 
    { 
     get { return (Int32)GetValue(IDProperty); } 
     set 
     { 
      SetValue(IDProperty, value); 
      NotifyPropertyChanged("ID"); 
     } 
    } 

    public static readonly DependencyProperty IDProperty = 
    DependencyProperty.Register("ID", typeof(Int32), typeof(Group), null); 

    public String GroupName 
    { 
     get { return (String)GetValue(GroupNameProperty); } 
     set 
     { 
      SetValue(GroupNameProperty, value); 
      NotifyPropertyChanged("GroupName"); 
     } 
    } 

    public static readonly DependencyProperty GroupNameProperty = 
    DependencyProperty.Register("GroupName", typeof(String), typeof(Group), null); 

} 

public class MyViewModel : DependencyObject 
{ 
    public static readonly DependencyProperty LobCollectionProperty = 
     DependencyProperty.Register("LobCollection", 
      typeof(ObservableCollection<LOB>), 
      typeof(MyViewModel), 
      new PropertyMetadata(null, LobCollectionPropertyChanged)); 

    public ObservableCollection<LOB> LobCollection 
    { 
     get { return (ObservableCollection<MainBusinessLine>)GetValue(LobCollectionPropertyChanged); } 
     set 
     { 
      SetValue(MainBusinessLineCollectionProperty, value); 
      NotifyPropertyChanged("LobCollection"); 
     } 
    } 

    static void LobCollectionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     var viewModel = obj as MyViewModel; 

     if (viewModel == null) 
      return; 

     if (e.OldValue != null) 
     { 
      ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= viewModel.LobCollection_Changed; 
     } 

     if (e.NewValue != null) 
     { 
      ((INotifyCollectionChanged)e.NewValue).CollectionChanged += viewModel.LobCollection_Changed; 
     } 

    } 

    void LobCollection_Changed(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     NotifyPropertyChanged("LobCollection"); 
    } 
} 
+0

Laissez-moi être sûr que je comprends votre question: Vous avez cette classe: "public class Foo: INotifyPropertyChanged {collection INotifyCollectionChanged;}", et quand l'événement se déclenche CollectionChanged, vous voulez déclencher l'événement PropertyChanged sur la classe propriétaire. Est-ce exact? –

+0

Oui, vous avez raison. De plus j'ai édité mon post original pour montrer une version mise à jour qui fait quelquechose. Certes, ce n'est pas la meilleure solution, mais pour l'instant je veux juste pouvoir ajouter à une collection observable dans une autre collection observable. – jhorton

+0

Ce que vous faites dans vos classes LOB et Group me semble le plus logique. Le gérer dans la classe de base est certainement possible, mais avoir un mélange de DependancyProperty et INotifyPropertyChanged rend cela plus difficile. Notez également que techniquement parlant, je pense que vous ne suivez pas le contrat de INotifyPropertyChanged: la valeur de la propriété n'a pas changé, la collection en a. La manière standard de le faire serait de laisser l'événement CollectionChanged se déclencher, et de le laisser à cela. –

Répondre

2

Après notre conversation ci-dessus, cela est assez discutable, mais je pensais à la façon dont j'implémenter une classe de base qui a tiré des événements PropertyChanged lorsqu'une collection changé dans une propriété qui a été définie par la sous-classe. Comme je l'ai dit, c'est un peu inhabituel, mais voici comment je le ferais.

class FancyCollectionAndPropertyChangedBase : INotifyPropertyChanged 
{ 
    private Dictionary<ICollectionChanged, String> collectionNameLookup = new Dictionary<ICollectionChanged, String>(); 

    protected FancyCollectionAndPropertyChangedBase() 
    { 
     this.PropertyChanged += MyPropertyChanged; 
    } 

    private void MyPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if(this.collectionNameLookup.ContainsValue(e.PropertyName) 
     { 
      KeyValuePair<INotifyCollectionChanged, String> oldValue = this.collectionNameLookup.First(kvp => kvp.Value == e.Name); 
      oldValue.Key -= MyCollectionChanged; 
      this.collecitonNameLookup.Remove(oldValue.Key); 

      INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null); 
      collection.CollectionChanged += MyCollectionChanged; 
      this.collectionNameLookup.Add(collection, e.Name); 
     } 
     else if(typeof(INotifyCollectionChanged).IsAssignableFrom(this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).PropertyType)) 
     { 
      // Note: I may have gotten the IsAssignableFrom statement, above, backwards. 
      INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null); 
      collection.CollectionChanged += MyCollectionChanged; 
      this.collectionNameLookup.Add(collection, e.Name); 
     } 
    } 

    private void MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     this.NotifyPropertyChanged(this.collectionNameLookup[sender]; 
    } 
} 
+0

David, je voulais juste vous faire savoir que j'ai utilisé la base de votre code que vous avez posté ci-dessus et l'ai implémenté dans ma classe de base. Tout fonctionne bien maintenant. J'apprécie vraiment que vous preniez le temps de m'aider avec ça. Je vais marquer cela comme la réponse depuis un mélange de tout s'est avéré être le tour. En outre, j'ai supprimé l'héritage de DependencyObject et implémenté uniquement les interfaces INotify. Si à l'avenir, quelqu'un doit voir le code fini, je serai heureux de le poster. Merci encore. – jhorton