Domanda

OK, quindi voglio sottoclassare ObservableCollection per aggiungere una proprietà ad esso. Purtroppo l'evento PropertyChanged è protetto. Fondamentalmente voglio sottoclassarlo per avere un SelectedItem a cui posso collegarmi per gli elenchi nella mia app MVPM WPF.

Ecco lo scheletro della mia classe:

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

Ma non posso fare quanto segue:

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

a causa delle restrizioni di accesso. Questo mi fa fare una domanda più profonda. Come mai l'interfaccia utente può essere informata degli eventi PropertyChanged (ad es. Proprietà Count) e non posso farlo in code-behind?

Mi gira la testa, qualcuno può illuminarmi, per favore?

È stato utile?

Soluzione

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

ObservableCollection implementa INotifyPropertyChanged esplicitamente , il che significa che devi trasmettere l'istanza all'interfaccia prima di poter accedere ai metodi, alle proprietà e agli eventi dell'interfaccia. Quanto al perché, non lo so. Il Extensio markup vincolante n non " ; conoscere " ObservableCollections o qualsiasi altro tipo. Controlla i tipi per vedere se implementano o estendono interfacce / classi base specifiche (INPC, INCC, DependencyObject, ecc.) E quindi non importa se l'interfaccia è implementata in modo esplicito.

Altri suggerimenti

ObservableCollection (int .NET 3.5) sembra implementare l'evento PropertyChanged in un modo interessante .

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

Ciò significa che l'evento PropertyChanged protetto è probabilmente destinato esclusivamente a essere utilizzato per l'implementazione interna. L'altro evento INotifyPropertyChanged.PropertyChanged è quello che in realtà soddisfa l'implementazione dell'interfaccia INotifyPropertyChanged come interfaccia esplicita . Stranamente non vedo alcun posto all'interno di ObservableCollection in cui INotifyPropertyChanged.PropertyChanged viene effettivamente generato. Ciò potrebbe indicare che si trattava di un bug in .NET 3.5 anche se non ho testato per confermare se, ad esempio, viene generato un evento di modifica della proprietà per il conteggio quando un elemento viene aggiunto a una raccolta ma sembra essere come dovrebbe funzionare .

Nell'implementazione di .NET 4.0 sembra che l'evento INotifyPropertyChanged.PropertyChanged si agganci invece allo stesso delegato privato utilizzato dall'evento PropertyChanged protetto che potrebbe essere stato un bug risolvere. È anche possibile che ciò sia dovuto a differenze nel modo in cui le implementazioni degli eventi automatici vengono gestite in .NET 4.0 .

Correzione: ho verificato che l'evento INotifyPropertyChanged.PropertyChanged è stato sollevato da ObservableCollection, quindi i presupposti che ho fatto sopra sulla base dei risultati ottenuti dall'utilizzo di Reflector per esaminare l'implementazione di ObservableCollection deve essere impreciso. La mia ipotesi è che il riflettore stia facendo qualcosa di strano bug di cui non ho ancora prove.

Quindi, per far funzionare il tuo esempio, dovresti scrivere per farlo funzionare come nell'esempio qui sotto, proprio come Will ha dimostrato nella sua risposta.

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

Interessante vero? L'uso di interfacce esplicite viene utilizzato principalmente per evitare inevitabili collisioni nei membri richiesti per una determinata interfaccia, ma possono in un certo senso essere utilizzati per nascondere l'esistenza di un membro.

Se desideri generare eventi di modifica delle proprietà per le tue proprietà personalizzate che introduci nella tua sottoclasse, cerca di sostituire e / o chiamare il metodo protetto OnPropertyChanged implementato da ObservableCollection. Questa tecnica è uno standard ben adottato e consente alle sottoclassi di generare eventi o gestirli senza avere accesso al delegato dell'evento sottostante. In genere si preferisce utilizzare questa tecnica anche a proposito invece di avere un gestore di eventi hook sottoclasse per i propri eventi delle classi di base. Per ulteriori esempi, guarda come vengono implementati gli eventi in vari controlli in WinForms e WPF.

Ho provato ad aggiungere una nuova proprietà in

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

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

Non ho notato che PropertyChanged è definito come protetto . Finalmente spostato la proprietà Val in ViewModel.

L'interfaccia utente può e viene notificata. Questa è una restrizione SOLO con ObservableCollection, che definisce l'evento PropertyChanged come protetto.

FWIW, penso che farai meglio a lasciare ObservableCollection da solo e aggiungere semplicemente un'altra proprietà alla tua VM.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top