INotifyPropertyChanged vs. DependencyProperty no ViewModel

Ao implementar o ViewModel em um aplicativo WPF de arquitetura Model-View-ViewModel, parece haver duas opções principais para torná-lo vinculável. Eu vi implementações que usam DependencyProperty para propriedades que o modo de exibição vai vincular e eu vi o ViewModel implementando INotifyPropertyChanged vez disso.

Minha pergunta é quando devo preferir um ao outro? Existem diferenças de desempenho? É realmente uma boa idéia dar as dependencies do ViewModel para o WPF? O que mais preciso considerar ao tomar a decisão de design?

Kent escreveu um blog interessante sobre esse tópico: Exibir modelos: POCOs versus DependencyObjects .

Pequeno resumo:

  1. DependencyObjects não são marcados como serializáveis
  2. A class DependencyObject sobrescreve e veda os methods Equals () e GetHashCode ()
  3. Um DependencyObject tem afinidade de encadeamento – só pode ser acessado no encadeamento no qual foi criado

Eu prefiro a abordagem POCO. Uma class base para PresentationModel (aka ViewModel) que implementa a interface INotifyPropertyChanged pode ser encontrada aqui: http://compositeextensions.codeplex.com

De acordo com o guia de desempenho do WPF, os DependencyObjects têm um desempenho melhor do que os POCOs que implementam INotifyPropertyChanged:

http://msdn.microsoft.com/pt-br/library/bb613546.aspx

A escolha é totalmente baseada em sua lógica de negócios e no nível de abstração da interface do usuário. Se você não quiser uma boa separação, o DP funcionará para você.

As DependencyProperties serão aplicáveis ​​principalmente no nível VisualElements, portanto, não será uma boa ideia se criarmos muitos DPs para cada um dos nossos requisitos de negócios. Além disso, há um custo maior para DP do que um INotifyPropertyChanged. Quando você cria um WPF / Silverlight tente projetar UI e ViewModel totalmente separados para que, a qualquer momento, possamos alterar os controles Layout e UI (Com base no tema e nos estilos)

Consulte este post também – https://stackoverflow.com/questions/275098/what-applications-could-i-study-to-understand-datamodel-view-viewmodel . O link tem muita referência ao padrão Model-View-ViewModel, que é muito relevante para essa discussão.

Do ponto de vista da expressividade, gosto muito de usar as propriedades de dependência e me arrepio com o pensamento de INotifyPropertyChanged . Além dos nomes de propriedade de string e possíveis vazamentos de memory devido à inscrição de evento, INotifyPropertyChanged é um mecanismo muito mais explícito.

Propriedades de dependência implicam “quando isso, faça isso” usando metadados estáticos de fácil compreensão. É uma abordagem declarativa que obtém meu voto pela elegância.

INotifyPropertyChanged quando usado também oferece a capacidade de adicionar mais lógica no código de seus getters e setter de suas propriedades.

Exemplo DependencyProperty :

 public static DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof( String), typeof( Customer ) ); public String Name { set { SetValue( NameProperty, value ); } get { return ( String ) GetValue( NameProperty ); } } 

Em seu getter e setter — tudo o que você pode fazer é simplesmente chamar SetValue e GetValue respectivamente, b / c em outras partes do framework o getter / setter não é chamado, em vez disso chama diretamente SetValue, GetValue, então sua lógica de propriedade não ser executado de forma confiável.

Com INotifyPropertyChanged , defina um evento:

 public event PropertyChangedEventHandler PropertyChanged; 

E então, basta ter qualquer lógica em qualquer lugar do seu código e, em seguida, chamar:

 // ... // Something cool... // ... if( this.PropertyChanged != null ) { PropertyChanged( this, new PropertyChangedEventArgs( "Name" ) ); } // More cool stuff that will reliably happen... 

Isso pode estar em um getter / setter ou em qualquer outro lugar.

As propriedades de dependência destinam-se a suportar a vinculação (como um alvo) nos elementos da interface do usuário não como uma fonte de vinculação de dados, é onde o INotifyProperty entra. Do ponto de vista puro, você não deve usar DP em um ViewModels.

“Para ser a fonte de uma binding, uma propriedade não precisa ser uma propriedade de dependência; você pode usar qualquer propriedade CLR como uma origem de binding. No entanto, para ser o destino de uma binding, a propriedade deve ser um Para uma binding unidirecional ou bidirecional ser efetiva, a propriedade de origem deve suportar notifications de alteração que se propagam para o sistema de binding e, portanto, para o destino.Para origens de binding CLR customizadas, isso significa que a propriedade deve suportar INotifyPropertyChanged. Coleções devem suportar INotifyCollectionChanged. ”

Todos os objects de dependência não podem ser serializados (Isso pode dificultar o uso de ViewModels e DTO (POCO).

Existem diferenças entre o DP dentro do Silverlight em comparação com o WPF.

http://msdn.microsoft.com/en-us/library/cc221408(v=VS.95).aspx

http://msdn.microsoft.com/en-us/library/cc903933(VS.95).aspx

Eu também tive que considerar essa decisão recentemente.

Descobri que o mecanismo INotifyPropertyChanged atendeu melhor às minhas necessidades porque permitiu que eu colei minha GUI a uma estrutura de lógica de negócios existente sem duplicar o estado. O framework que eu estava usando tinha seu próprio padrão de observação e era fácil encaminhar um nível de notificação para o próximo. Eu simplesmente tinha uma class que implementava a interface do observador do meu framework de lógica de negócios e da interface INotifyPropertyChanged.

Com DP você não pode definir o backend que armazena o estado você mesmo. Eu teria que deixar .net armazenar em cache uma cópia de cada item do estado ao qual eu estava ligado. Isso parecia uma sobrecarga desnecessária – meu estado é grande e complicado.

Então, aqui eu encontrei INotifyPropertyChanged melhor para expor propriedades da lógica de negócios para GUI.

Dito isto, quando eu precisava de um widget GUI personalizado para expor uma propriedade e para que as alterações nessa propriedade afetassem outros widgets da GUI, o DP provou a solução simples.

Então eu achei DP útil para a GUI para a notificação da GUI.

É realmente uma boa idéia dar as dependencies do ViewModel para o WPF?

O .NET 4.0 terá System.Xaml.dll, portanto, você não precisará depender de uma estrutura arbitrária para utilizá-lo. Veja o post de Rob Relyea sobre sua session de PDC.

Minha vez

XAML é uma linguagem para descrever objects, e WPF é uma estrutura cujos objects descritos são elementos da interface do usuário.

Seu relacionamento é semelhante ao C #, uma linguagem para descrever a lógica, e .NET, um framework que implementa determinados tipos de lógica.

A finalidade do XAML é charts de objects declarativos. As tecnologias W * F são ótimas candidatas para esse paradigma, mas o XAML existe independentemente delas.

O XAML e todo o sistema de dependencies foram implementados como pilhas separadas para WF e WPF, provavelmente para alavancar a experiência de diferentes equipes sem criar uma dependência (sem trocadilhos) entre eles.

Parece que propriedades de dependência devem ser usadas em controles que você cria, como botões. Para usar propriedades em XAML e usar todos os resources do WPF, essas propriedades devem propriedades de dependência.

No entanto, seu ViewModel é melhor usando INotifyPropertyChanged. Usando INotifyPropertyChanged lhe dará a habilidade de ter lógica getter / setter se você precisar.

Eu recomendo verificar a versão de Josh Smith de uma class base para um ViewModel que já implementa INotifyPropertyChanged:

http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

Eu acho que este é um excelente exemplo de como fazer um ViewModel.

Eu acho que DependencyProperty e INotifyPropertyChanged são usados ​​para duas coisas diferentes em Binding: o primeiro para ativar uma propriedade para ser um destino de uma binding e receber a input de outra propriedade (use {Binding …} para definir a propriedade), a última quando você deseja que o valor de uma propriedade seja usado como a origem de uma binding (nome na expressão de caminho de binding). Então a escolha é meramente técnica.

Propriedades de dependência são a cola da criação de controle personalizado. Se você estiver interessado em usar o Intelli-sense para mostrar suas propriedades na janela de propriedades no tempo de design do XAML, deverá usar as propriedades de Dependência. INPC nunca mostrará uma propriedade na janela de propriedades em tempo de design.

Eu prefiro uma abordagem mais direta, sobre a qual eu escrevi no Presentation Model Without INotifyPropertyChanged . Usando uma alternativa para binding de dados, você pode vincular-se diretamente às propriedades do CLR sem nenhum código de contabilidade. Você acabou de escrever um código .NET simples em seu View Model e ele é atualizado quando o modelo de dados é alterado.

Há apenas uma coisa porque preferir um DependencyObject – a vinculação funcionará melhor. Apenas tente um exemplo com um ListBox e TextBox , preencha a lista com dados da propriedade INotifyPropertyChanged vs. DependencyProperty e edite o item atual do TextBox

Se você quiser expor propriedades para outros controles, você deve usar propriedades de dependência … Mas boa sorte, porque eles demoram um pouco para descobrir …