Czy ktoś wie, dlaczego ten kod nie działa:
public class CollectionViewModel : ViewModelBase {
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
set
{
_contentList = value;
RaisePropertyChanged("ContentList");
//I want to be notified here when something changes..?
//debugger doesn't stop here when IsRowChecked is toggled
}
}
}
public class EntityViewModel : ViewModelBase
{
private bool _isRowChecked;
public bool IsRowChecked
{
get { return _isRowChecked; }
set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
}
}
ViewModelBase
zawiera wszystko dla RaisePropertyChanged
itd. i działa na wszystko inne oprócz tego problemu.
c#
observablecollection
inotifypropertychanged
Joseph Jun. Melettukunnel
źródło
źródło
Odpowiedzi:
Metoda SetList ContentList nie zostanie wywołana po zmianie wartości w kolekcji, zamiast tego należy szukać wywołania zdarzenia CollectionChanged .
Okej, dziś dwa razy ugryzł mnie błąd w dokumentacji MSDN. W linku, który ci dałem, mówi:
Ale w rzeczywistości nie uruchamia się, gdy przedmiot jest zmieniany. Myślę, że będziesz wtedy potrzebować bardziej brutalnej metody:
Jeśli będziesz tego bardzo potrzebować, możesz chcieć utworzyć podklasę własną,
ObservableCollection
która wyzwalaCollectionChanged
zdarzenie, gdy członekPropertyChanged
automatycznie wyzwala swoje zdarzenie (tak jak mówi, że powinno to być w dokumentacji ...)źródło
changed
? Może to oznaczać, że zmieniła się właściwość jednego z elementów kolekcji (tak myślę, że ją interpretujesz) lub może oznaczać, że jeden z elementów kolekcji został zmieniony przez zastąpienie go inną instancją ( to moja interpretacja). Nie do końca jednak przekonany - będzie musiał przyjrzeć się temu dokładniej._contentList.Clear()
? Nikt nie zrezygnuje z subskrypcjiPropertyChanged
!ContentCollectionChanged
obsługuje tylko Dodaj / Usuń, a nie Zamień / Resetuj. Spróbuję edytować i naprawić post. Sposób, w jaki Simon to robi w swojej odpowiedzi, jest poprawny.Oto klasa rozwijana, która podklasy ObservableCollection i faktycznie wywołuje akcję Reset, gdy właściwość elementu listy ulegnie zmianie. Wymusza wszystkie elementy do wdrożenia
INotifyPropertyChanged
.Zaletą jest to, że możesz powiązać dane z tą klasą, a wszystkie twoje powiązania zostaną zaktualizowane wraz ze zmianami we właściwościach elementu.
źródło
NotifyCollectionChangedAction.Replace
nie jest to dobry pomysł, ponieważ wtedy nie można rozróżnić między faktyczną wymianą elementu a zdarzeniem spowodowanym zmianą elementu. Jest znacznie lepiej, gdy zdefiniujesz,public event PropertyChangedEventHandler CollectionItemChanged;
a potemItemPropertyChanged
zrobiszthis.CollectionItemChanged?.Invoke(sender, e);
Mam nadzieję, że zebrałem całkiem solidne rozwiązanie, w tym niektóre techniki w innych odpowiedziach. Jest to nowa klasa pochodna, z
ObservableCollection<>
której dzwonięFullyObservableCollection<>
Posiada następujące cechy:
ItemPropertyChanged
. Celowo oddzieliłem to od istniejącychCollectionChanged
:ItemPropertyChangedEventArgs
który mu towarzyszy: oryginałPropertyChangedEventArgs
i indeks w kolekcji.ObservableCollection<>
.ObservableCollection<>.Clear()
), unikając możliwego wycieku pamięci.OnCollectionChanged()
, a nie subskrypcjęCollectionChanged
zdarzenia wymagającą więcej zasobów .Kod
Cały
.cs
plik znajduje się poniżej. Zwróć uwagę, że użyto kilku funkcji języka C # 6, ale przeniesienie go z powrotem powinno być dość proste:Testy NUnit
Możesz więc sprawdzić zmiany, które możesz wprowadzić (i zobaczyć, co najpierw przetestowałem!), Dołączyłem również moją klasę testową NUnit. Oczywiście poniższy kod nie jest konieczny tylko do wykorzystania
FullyObservableCollection<T>
w projekcie.Uwaga Klasa testowa wykorzystuje
BindableBase
PRISM do implementacjiINotifyPropertyChanged
. Nie ma zależności od PRISM od głównego kodu.źródło
ListView
będzie reagować naCollectionChanged
zdarzenia, ponieważ o nich wie.ItemPropertyChanged
to niestandardowy dodatek, więc musisz go o tym nauczyć. Jako szybki i brudny fix, można spróbować tylko wypalanieCollectionChanged
zdarzenia, jak również (lub nawet zamiast)ItemPropertyChanged
wOnItemPropertyChanged()
. Trzymałem je oddzielnie z powodów podanych w odpowiedzi, ale w twoim przypadku może to po prostu zrobić to, czego potrzebujesz.Wykorzystuje to powyższe pomysły, ale sprawia, że jest to pochodny zbiór „bardziej wrażliwy”:
źródło
ObservableCollection nie będzie propagować zmian poszczególnych elementów jako zdarzeń CollectionChanged. Będziesz musiał albo zasubskrybować każde zdarzenie i przekazać je ręcznie, albo możesz sprawdzić klasę BindingList [T] , która zrobi to za Ciebie.
źródło
Dodano do zdarzenia TruelyObservableCollection „ItemPropertyChanged”:
źródło
Użyłem odpowiedzi Jacka Kenyona, aby zaimplementować własne OC, ale chciałbym wskazać jedną zmianę, którą musiałem wprowadzić, aby to zadziałało. Zamiast:
Użyłem tego:
Wygląda na to, że "e.NewItems" daje wartość null, jeśli akcją jest .Remove.
źródło
Dodam tylko moje 2 centy na ten temat. Felt TrulyObservableCollection wymagało dwóch innych konstruktorów, jak znaleziono w ObservableCollection:
źródło
Wiem, że jestem za późno na tę imprezę, ale może - komuś to pomoże ..
Tutaj możesz znaleźć moją implementację ObservableCollectionEx. Ma kilka funkcji:
Oczywiście wszelkie komentarze są mile widziane;)
źródło
Jeśli znam ObservableCollection, zrób zdarzenie tylko wtedy, gdy dodajemy / usuwamy lub przenosimy elementy w naszej kolekcji. Kiedy po prostu zaktualizujemy niektóre właściwości w kolekcji elementów kolekcji, nie sygnalizuj tego, a interfejs użytkownika nie zostanie zaktualizowany.
Możesz po prostu zaimplementować INotifyPropertyChange w swojej klasie Model. A gdy zaktualizujemy niektóre właściwości w elemencie kolekcji, automatycznie zaktualizuje interfejs użytkownika.
i niż
W moim przypadku użyłem ListView do powiązania dla tej kolekcji, aw ItemTemplate ustawiłem Binding to Model właściwość i działa dobrze.
Oto fragment
Windows XAML:
Przykład kodu modelu:
I implementacja ViewModel:
źródło
Proste rozwiązanie dla standardowej obserwacji, której użyłem:
NIE DODAWAJ do swojej nieruchomości ani NIE ZMIENIAJ jej elementów wewnętrznych BEZPOŚREDNIO, zamiast tego utwórz kolekcję tymczasową, taką jak ta
i dodaj elementy lub dokonaj zmian w tmpList,
następnie przekaż ją do swojej rzeczywistej własności przez cesję.
zmieni to całą właściwość, która spowoduje, że INotifyPropertyChanged zostanie zauważone zgodnie z potrzebami.
źródło
Wypróbowuję to rozwiązanie, ale działa tylko dla mnie jak RaisePropertyChange ("SourceGroupeGridView") po zmianie kolekcji, która jest uruchamiana dla każdego dodanego lub zmienionego elementu.
Problem tkwi w:
NotifyCollectionChangedAction.Reset to działanie powoduje całkowite ponowne powiązanie wszystkich elementów w groupedgrid, jest równoważne w RaisePropertyChanged. Kiedy go używasz, odświeżane są wszystkie grupy widoku siatki.
JEŚLI chcesz tylko odświeżyć w interfejsie użytkownika grupę nowego elementu, nie używasz akcji Resetuj, będziesz potrzebować zasymulować akcję Dodaj w itemproperty z czymś takim:
Przepraszam za mój angielski i dziękuję za kod podstawowy :), mam nadzieję, że to komuś pomoże ^ _ ^
Enjoi !!
źródło
Oto metoda rozszerzenia powyższego rozwiązania ...
źródło
Zamiast ObservableCollection lub TrulyObservableCollection, rozważ użycie BindingList i wywołanie metody ResetBindings.
Na przykład:
Biorąc pod uwagę zdarzenie, takie jak kliknięcie, Twój kod wyglądałby następująco:
Mój model wyglądał tak:
źródło
BindingList
, ale istnieje ograniczenie tego podejścia, które przezwyciężają inne odpowiedzi: technika ta polega na zmianie wartości w kodzie i miejscu, w którymResetBindings()
można dodać wywołanie . Większość pozostałych odpowiedzi zadziała, jeśli obiekty listy zostaną zmienione w inny sposób, na przykład niezmieniony kod lub z powiązania z drugą kontrolką.Aby wyzwolić OnChange na liście ObservableCollection
Przykład:
źródło
Oto moja wersja realizacji. Sprawdza i zgłasza błąd, jeśli obiekty na liście nie implementują INotifyPropertyChanged, więc nie można zapomnieć o tym problemie podczas programowania. Na zewnątrz używasz zdarzenia ListItemChanged, aby określić, czy lista lub sam element listy uległy zmianie.
źródło
Proste rozwiązanie w 2 wierszach kodu. Po prostu użyj konstruktora kopiującego. Nie ma potrzeby pisania TrulyObservableCollection itp.
Przykład:
Inna metoda bez konstruktora kopiującego. Możesz użyć serializacji.
źródło
Możesz również użyć tej metody rozszerzenia, aby łatwo zarejestrować procedurę obsługi dla zmiany właściwości elementu w odpowiednich kolekcjach. Ta metoda jest automatycznie dodawana do wszystkich kolekcji implementujących INotifyCollectionChanged, które zawierają elementy implementujące INotifyPropertyChanged:
Jak używać:
źródło