mplementação do @WPF MVVM INotifyPropertyChanged - Model ou ViewModel
Li vários debates sobre onde implementar INotifyPropertyChanged aqui no StackOverflow e em outros blogs, mas parece que há casos em que você precisa implementá-lo no modelo. Aqui está o meu cenário - estou procurando feedback sobre minha conclusão ou minha abordagem está errad
Estou usando esta implementação de um ObservableDictionary ObservableDictionary) porque preciso de consultas de desempenho usando a chav
Neste dicionário, coloco a coleção de objetos Model.
Na minha VM, declaro uma instância (Books) do dicionário e no XAML se liga a el
<tk:DataGrid AutoGenerateColumns="False" Grid.Row="1" ItemsSource="{Binding Mode=TwoWay, Path=Books.Store}" Grid.ColumnSpan="2" Margin="3">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=Value.Name}" MinWidth="100" Header="Name" />
<tk:DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=Value.Details}" MinWidth="300" Header="Details" />
</tk:DataGrid.Columns>
</tk:DataGrid>
Se eu implementar INotifyPropertyChanged na VM for Books e alterar o valor de um nome de livro no código, a interface do usuário não será atualizad
Se eu implementar INotifyPropertyChanged na VM for Store e alterar o valor de um nome de livro no código, a interface do usuário não será atualizad
Se eu implementar INotifyProperyChanged no modelo e alterar o valor de um nome de livro no código, a interface do usuário será atualizad
O evento Alterado não é acionado no primeiro caso, porque o configurador de Dicionário não é chamado, é o Item (um Livro
Estou faltando alguma coisa porque, se esta é a interpretação correta, se eu quero notificações consistentes para meus modelos, independentemente de estarem vinculadas diretamente a XAML ou através de algum tipo de coleção, eu sempre gostaria que o modelo implementasse INotifyProperyChange
Aliás, além da referência da DLL, eu pessoalmente não vejo INotifyPropertyChanged como uma função de interface do usuário - acho que deve ser definida em um espaço de nome .net mais geral - meus 2 centavo
EDIT COMEÇA AQUI:
Estávamos em um debate semântico tão bom que perdi o cerne da minha pergunta, então aqui ela é postada novamente, mas com um exemplo muito simples de MVVM ilustra minha pergunt
Os modelos:
public class Book
{
public string Title { get; set; )
public List<Author> Authors { get; set; }
}
public class Author
{
public string Name { get; set; }
}
O Provedor de Dados para gerar alguns dados fictícios
public class BookProvider
{
public ObservableCollection<Book> GetBooks() {
ObservableCollection<Book> books = new ObservableCollection<Book>();
books.Add(new Book {
Title = "Book1",
Authors = new List<Author> { new Author { Name = "Joe" }, new Author { Name = "Phil" } }
});
books.Add(new Book {
Title = "Book2",
Authors = new List<Author> { new Author { Name = "Jane" }, new Author { Name = "Bob" } }
});
return books;
}
}
The ViewModel
public class BookViewModel : INotifyPropertyChanged
{
private ObservableCollection<Book> books;
public ObservableCollection<Book> Books {
get { return books; }
set {
if (value != books) {
books = value;
NotifyPropertyChanged("Books");
}
}
}
private BookProvider provider;
public BookViewModel() {
provider = new BookProvider();
Books = provider.GetBooks();
}
// For testing the example
public void MakeChange() {
Books[0].Title = "Changed";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
ódigo @XAML atrás de Normalmente não faria isso dessa maneira - apenas por exemplo simples
public partial class MainWindow : Window
{
private BookViewModel vm;
public MainWindow() {
InitializeComponent();
vm = new BookViewModel();
this.DataContext = vm;
}
private void Button_Click(object sender, RoutedEventArgs e) {
vm.MakeChange();
}
}
The XAML
<Window x:Class="BookTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="242*" />
<RowDefinition Height="69*" />
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Books}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" />
<ListBox ItemsSource="{Binding Authors}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontStyle="Italic" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="1" Content="Change" Click="Button_Click" />
</Grid>
Conforme codificado acima, quando clico no botão e altero o valor no primeiro livro, a interface do usuário não mud
No entanto, quando movo o INotifyPropertyChanged para o Model, ele funciona bem (atualizações da interface do usuário) porque a alteração está no setter de propriedades do Model, e não Books na VM:
public class Book : INotifyPropertyChanged
{
private string title;
public string Title {
get { return title; }
set {
if (value != title) {
title = value;
NotifyPropertyChanged("Title");
}
}
}
public List<Author> Authors { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Volte à minha pergunta original, como faço para implementar isso sem implementar INotifyPropertyChanged no model
Obrigado