Question

OK, je souhaite donc placer la sous-classe ObservableCollection pour y ajouter une propriété. Malheureusement, l'événement PropertyChanged est protégé. En gros, je souhaite créer un SelectedItem auquel je peux faire référence pour les listes dans mon application MVVM WPF.

Voici le squelette de ma classe:

public class SelectableList<T> : ObservableCollection<T>
{
    public T SelectedItem {get;set;}
}

Mais je ne peux pas faire ce qui suit:

SelectableList<int> intList = new SelectableList<int>();
intList.PropertyChanged += new PropertyChangedEventHandler(intList_Changed);

en raison de restrictions d'accès. Cela me fait poser une question plus profonde. Comment se fait-il que l’interface utilisateur puisse être avertie des événements PropertyChanged (par exemple, la propriété Count) et que je ne puisse pas le faire dans code-behind?

Ma tête tourne, quelqu'un peut-il m'éclairer s'il vous plaît?

Était-ce utile?

La solution

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);

ObservableCollection implémente explicitement INotifyPropertyChanged Cela signifie que vous devez convertir l'instance sur l'interface avant de pouvoir accéder aux méthodes, propriétés et événements de l'interface. Quant à savoir pourquoi cela est fait, je ne sais pas. La reliure du balisage extensif n ne le permet pas ; savoir " ObservableCollections ou tout autre type. Il vérifie si les types implémentent ou étendent des interfaces / classes de base spécifiques (INPC, INCC, DependencyObject, etc.) et ne se soucient donc pas de savoir si l'interface est implémentée explicitement.

Autres conseils

ObservableCollection (int .NET 3.5) semble implémenter l'événement PropertyChanged dans un manière intéressante .

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

Cela signifie que l'événement protégé PropertyChanged est probablement destiné à être utilisé uniquement pour une implémentation interne. L'autre événement INotifyPropertyChanged.PropertyChanged est celui qui remplit réellement l'implémentation de l'interface INotifyPropertyChanged en tant que interface explicite . Étrangement, je ne vois aucun endroit dans la collection Observable où le INotifyPropertyChanged.PropertyChanged est réellement élevé. Cela peut indiquer qu'il s'agit d'un bogue dans .NET 3.5 bien que je n'ai pas vérifié si, par exemple, un événement de propriété modifiée est déclenché pour Nombre lorsqu'un élément est ajouté à une collection, mais cela semble être ainsi qu'il est censé fonctionner. .

Dans l'implémentation .NET 4.0, il apparaît que l'événement INotifyPropertyChanged.PropertyChanged est plutôt lié au même délégué privé utilisé par l'événement protégé PropertyChanged , ce qui peut être un bogue. réparer. Il est également possible que cela soit simplement dû à différences dans la façon dont les implémentations d'événements automatiques sont gérées dans .NET 4.0 .

Correction: j'ai vérifié que l'événement INotifyPropertyChanged.PropertyChanged est généré par ObservableCollection, de sorte que les hypothèses que j'ai formulées ci-dessus sont basées sur les résultats obtenus avec Reflector pour examiner l'implémentation ObservableCollection. doit être inexact. Mon hypothèse est que le réflecteur est en train de faire quelque chose d'étrange bug je n'ai pas encore de preuve de cela.

Donc, pour que votre exemple fonctionne, il vous faudrait écrire pour que cela fonctionne ressemble à l'exemple ci-dessous, tout comme Will l'a démontré dans sa réponse.

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);

Intéressant non? L’utilisation d’interfaces explicites est principalement utilisée pour éviter les collisions inévitables entre les membres requises pour une interface donnée, mais elles peuvent également être utilisées pour masquer l’existence d’un membre.

Si vous souhaitez générer des événements de modification de propriété pour vos propres propriétés personnalisées que vous introduisez dans votre sous-classe, examinez le remplacement et / ou l'appel de la méthode protégée OnPropertyChanged qu'observable applique également. Cette technique est une norme bien adoptée et permet aux sous-classes de déclencher des événements ou de les gérer sans avoir accès au délégué d’événement sous-jacent. Il est généralement préférable d’utiliser également cette technique plutôt que d’avoir un gestionnaire d’accès de sous-classe à ses propres événements de classes de base. Pour plus d'exemples, regardez comment les événements de divers contrôles sont implémentés dans WinForms et WPF.

J'ai essayé d'ajouter une nouvelle propriété dans

public class ResultCollection<T> : ObservableCollection<T>
{

        Boolean _val;
        public Boolean Val
        {   
            get
            {   
                return _val;
            }
            set
            {   
                _val= value;
                OnPropertyChanged(new PropertyChangedEventArgs("Val"));
            }
        }
}

Je n'ai pas vraiment remarqué que PropertyChanged est défini comme protégé . Enfin déplacé la propriété Val vers ViewModel.

L’UI peut et doit être notifiée. Il s'agit d'une restriction JUST avec ObservableCollection, qui définit l'événement PropertyChanged comme étant protégé.

FWIW, je pense que vous feriez mieux de laisser ObservableCollection seul et d’ajouter une autre propriété à votre VM.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top