Alguém sabe por que esse código não funciona:
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
contém tudo para RaisePropertyChanged
etc. e está funcionando para todo o resto, exceto esse problema.
c#
observablecollection
inotifypropertychanged
Joseph jun. Melettukunnel
fonte
fonte
Respostas:
O método Set do ContentList não será chamado quando você altera um valor dentro da coleção; você deve estar atento ao disparo do evento CollectionChanged .
Ok, isso é duas vezes hoje. Fui mordido pela documentação do MSDN estar errada. No link que eu te dei, diz:
Mas na verdade não é acionado quando um item é alterado. Eu acho que você precisará de um método mais bruteforce:
Se você vai precisar muito disso, pode querer incluir uma subclasse sua
ObservableCollection
que aciona oCollectionChanged
evento quando um membro aciona seuPropertyChanged
evento automaticamente (como diz na documentação ...)fonte
changed
? Isso pode significar que uma propriedade de um dos elementos da coleção foi alterada (que é como eu acho que você está interpretando) ou pode significar que um dos elementos da coleção foi alterado, substituindo-o por uma instância diferente ( esta é a minha interpretação). Mas não totalmente convencido - terá que investigar melhor._contentList.Clear()
? Ninguém cancelará a inscriçãoPropertyChanged
!ContentCollectionChanged
lida apenas com Adicionar / Remover e não em Substituir / Redefinir. Vou tentar editar e corrigir a postagem. O modo como Simon faz isso em sua resposta está correto.Aqui está uma classe drop-in que subclasses ObservableCollection e realmente gera uma ação Redefinir quando uma propriedade em um item da lista é alterada. Força todos os itens a serem implementados
INotifyPropertyChanged
.O benefício aqui é que você pode vincular dados a essa classe e todas as suas ligações serão atualizadas com alterações nas propriedades do item.
fonte
NotifyCollectionChangedAction.Replace
não é uma boa ideia, porque não é possível distinguir entre um item que está sendo substituído ou um evento causado por uma alteração do item. Ele fica muito melhor quando você definirpublic event PropertyChangedEventHandler CollectionItemChanged;
e, em seguida,ItemPropertyChanged
fazerthis.CollectionItemChanged?.Invoke(sender, e);
Reuni o que espero que seja uma solução bastante robusta, incluindo algumas das técnicas em outras respostas. É uma nova classe derivada da
ObservableCollection<>
qual estou chamandoFullyObservableCollection<>
Possui os seguintes recursos:
ItemPropertyChanged
. Eu deliberadamente mantive isso separado do existenteCollectionChanged
:ItemPropertyChangedEventArgs
que o acompanha: o originalPropertyChangedEventArgs
e o índice na coleção.ObservableCollection<>
.ObservableCollection<>.Clear()
), evitando um possível vazamento de memória.OnCollectionChanged()
assinatura da classe base , em vez de uma assinatura que consome mais recursos doCollectionChanged
evento.Código
O
.cs
arquivo completo segue. Observe que alguns recursos do C # 6 foram usados, mas deve ser bastante simples fazer o backport:Testes NUnit
Para que você possa verificar as alterações que você pode fazer (e ver o que eu testei em primeiro lugar!), Também incluí minha classe de teste NUnit. Obviamente, o código a seguir não é necessário apenas para usar
FullyObservableCollection<T>
no seu projeto.NB A classe de teste usa
BindableBase
do PRISM para implementarINotifyPropertyChanged
. Não há dependência do PRISM no código principal.fonte
ListView
responderá aosCollectionChanged
eventos porque sabe sobre eles.ItemPropertyChanged
é uma adição não padrão, então você precisa ensiná-lo sobre isso. Como uma solução rápida e suja, você pode tentar apenas disparar oCollectionChanged
evento, bem como (ou mesmo em vez de)ItemPropertyChanged
noOnItemPropertyChanged()
. Eu os mantive separados pelos motivos indicados na resposta, mas, para o seu caso de uso, ele pode fazer apenas o que você precisa.Isso usa as idéias acima, mas a torna uma coleção "mais sensível" derivada:
fonte
ObservableCollection não propagará alterações de itens individuais como eventos CollectionChanged. Você precisará se inscrever em cada evento e encaminhá-lo manualmente, ou poderá verificar a classe BindingList [T] , que fará isso por você.
fonte
Adicionado ao evento TruelyObservableCollection "ItemPropertyChanged":
fonte
Usei a resposta de Jack Kenyons para implementar meu próprio OC, mas gostaria de destacar uma alteração que tive que fazer para fazê-lo funcionar. Ao invés de:
Eu usei isso:
Parece que o "e.NewItems" produz nulo se a ação for .Remove.
fonte
Apenas adicionando meus 2 centavos neste tópico. Sentiu que o TrulyObservableCollection exigia os outros dois construtores, conforme encontrado em ObservableCollection:
fonte
Eu sei que estou muito atrasado para esta festa, mas talvez - ajude alguém.
Aqui você pode encontrar minha implementação do ObservableCollectionEx. Possui alguns recursos:
Obviamente, quaisquer comentários são apreciados;)
fonte
Se eu conheço o ObservableCollection make event, apenas quando adicionamos / excluímos ou movemos itens em nossa coleção. Quando atualizamos apenas algumas propriedades na coleção de itens de coleção, não sinalizamos sobre isso e a interface do usuário não será atualizada.
Você pode simly implementar INotifyPropertyChange na sua classe Model. E do que quando atualizamos algumas propriedades no item de coleção, ele atualiza automaticamente a interface do usuário.
e então
No meu caso, usei o ListView para vincular para esta coleção e no ItemTemplate defina a propriedade Binding to Model e ele funciona bem.
Aqui está um trecho
Windows XAML:
Exemplo de código do modelo:
E implementação do ViewModel:
fonte
Solução simples para coleção de observação padrão que eu usei:
NÃO ADICIONE à sua propriedade OU MUDE seus itens internos DIRETAMENTE, em vez disso, crie uma coleção temporária como esta
e adicione itens ou faça alterações no tmpList,
depois passe para sua propriedade real por atribuição.
isso mudará toda a propriedade, causando aviso de INotifyPropertyChanged conforme necessário.
fonte
Eu tento esta solução, mas só funciona para mim como um RaisePropertyChange ("SourceGroupeGridView") quando a coleção é alterada, acionada para cada item adicionado ou alterado.
O problema está em:
NotifyCollectionChangedAction.Reset esta ação, faça uma religação completa de todos os itens no groupedgrid, é equivalente a RaisePropertyChanged. Quando você o usa, todos os grupos de gridview são atualizados.
Se você quiser atualizar apenas na interface do usuário o grupo do novo item, não usar a ação Redefinir, será necessário simular uma ação Adicionar na propriedade do item com algo como isto:
Desculpe pelo meu inglês, e obrigado pelo código base :), espero que isso ajude alguém ^ _ ^
Enjoi !!
fonte
Aqui está um método de extensão para a solução acima ...
fonte
Em vez de um ObservableCollection ou TrulyObservableCollection, considere usar um BindingList e chamar o método ResetBindings.
Por exemplo:
Dado um evento, como um clique, seu código ficaria assim:
Meu modelo ficou assim:
fonte
BindingList
, mas há uma limitação a essa abordagem que as outras respostas superam: essa técnica depende do valor que está sendo alterado no código e onde uma chamada paraResetBindings()
pode ser adicionada. A maioria das outras respostas funcionará se os objetos da lista forem alterados por outros meios, como código inalterável ou de uma ligação para um segundo controle.Para acionar o OnChange na lista ObservableCollection
Exemplo:
fonte
Aqui está a minha versão da implementação. Ele verifica e gera um erro, se os objetos da lista não implementarem INotifyPropertyChanged, portanto, não é possível esquecer esse problema durante o desenvolvimento. Por fora, você usa o Evento ListItemChanged para determinar se a lista ou o próprio item da lista foi alterado.
fonte
Solução simples em 2 linhas de código. Basta usar o construtor de cópia. Não há necessidade de escrever TrulyObservableCollection etc.
Exemplo:
Outro método sem construtor de cópias. Você pode usar serialização.
fonte
Você também pode usar esse método de extensão para registrar facilmente um manipulador para alteração de propriedade do item em coleções relevantes. Este método é adicionado automaticamente a todas as coleções que implementam INotifyCollectionChanged que mantêm itens que implementam INotifyPropertyChanged:
Como usar:
fonte