2011-01-21 2 views
3

저는 ListView에 Movies 목록이 들어있는 Datatemplate이 있습니다. ObservableColection에 데이터 바인딩되어 있지만 Movie.Name을 편집 할 때마다 PropertyChangedEventHandler에서 "Name"이 호출 되어도 "Name"이 호출 되어도 ListView는 업데이트되지 않습니다.ObservableCollection 데이터 바인딩 <T> MVVM

는 내 이니셜 내 컬렉션에 2 "영화"의를 추가하고이 올바른 표시됩니다 (Klovn 영화, 카메라) 내가 선택한 영화의 텍스트를 변경하고 변경해야 편집을 클릭 그래서

그 이름은 "Test"이고 이지만 변경된 내용은 ListView에 표시되지 않지만 foreach를 사용하여 Collection을 출력하면 이름은 Test입니다.

View.xaml

<Window x:Class="MovieDB3.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"> 
    <DockPanel> 
     <Menu DockPanel.Dock="Top"> 
      <MenuItem Header="File"> 
       <MenuItem Header="Edit" Click="MenuEditClick"/> 
      </MenuItem> 
     </Menu> 
     <Grid DockPanel.Dock="Top"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition/> 
       <ColumnDefinition/> 
      </Grid.ColumnDefinitions> 
      <Grid.RowDefinitions> 
       <RowDefinition/> 
      </Grid.RowDefinitions> 
      <ListView VerticalAlignment="Stretch" Name="ListViewMovies" ItemsSource="{Binding Path=Collection}" IsSynchronizedWithCurrentItem="True" > 
       <ListView.ItemTemplate> 
        <DataTemplate> 
         <WrapPanel> 
          <TextBlock Text="{Binding Path=Name}"/> 
         </WrapPanel> 
        </DataTemplate> 
       </ListView.ItemTemplate> 
      </ListView> 
     </Grid> 
    </DockPanel> 
</Window> 

View.cs

using System; 
using System.Windows; 
using MovieDB3.Models; 
using MovieDB3.ViewModels; 

namespace MovieDB3 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private MainViewModel MVM; 
     public MainWindow() 
     { 
      InitializeComponent(); 
      MVM = new MainViewModel(); 
      DataContext = MVM; 
     } 

     private void MenuEditClick(object sender, RoutedEventArgs e) 
     { 
      MVM.setMovieName((Movie)ListViewMovies.SelectedItem, "test"); 
     } 
    } 
} 

뷰 모델

using System; 
using System.ComponentModel; 
using MovieDB3.Models; 
using System.Collections.ObjectModel; 

namespace MovieDB3.ViewModels 
{ 
    class MainViewModel : INotifyPropertyChanged 
    { 
     public ObservableCollection<Movie> Collection {get; set;} 

     public MainViewModel() 
     { 
      Collection = new ObservableCollection<Movie>(); 

      //Test kode 
      Movie movie = new Movie(); 
      movie.Name = "Klovn The Movie"; 
      Collection.Add(movie); 
      movie = new Movie(); 
      movie.Name = "Taken"; 
      Collection.Add(movie); 
     } 

     public void setMovieName(Movie movie, string newName) 
     { 
      //movie.Name = newName; 
      Console.WriteLine("CurrentName: " + movie.Name); 
      int i = Collection.IndexOf(movie); 
      Collection[i].Name = newName; 
      Console.WriteLine("NewName: " + movie.Name); 
      NotifyPropertyChanged("Name"); 
     } 

     public void setMovieName(string currentName, string newName) 
     { 
      foreach (Movie movie in Collection) 
      { 
       if (movie.Name.Equals(currentName)) 
       { 
        movie.Name = newName; 
        NotifyPropertyChanged("Name"); 
        return; 
       } 
      } 
     } 

     //public string MovieName 
     //{ 
     // set 
     // { 

     //  NotifyPropertyChanged("MovieName"); 
     // } 
     //} 

     public event PropertyChangedEventHandler PropertyChanged; 

     private void NotifyPropertyChanged(String info) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(info)); 
      } 
     } 
    } 
} 

Movie.cs

using System; 

namespace MovieDB3.Models 
{ 
    class Movie 
    { 
     public string Name { get; set; } 
     public int Id { get; set; } 
     public double Rating { get; set; } 
     public DateTime Release { get; set; } 
     public TimeSpan Runtime { get; set; } 
     public String Trailer { get; set; } 
    } 
} 

답변

8

INotifyPropertyChanged을 Movie 클래스에 구현해야하며 수동으로 이벤트를 발생시키지 않아야합니다.

public class Movie : INotifyPropertyChanged 
{ 
    private string _name = String.Empty; 
    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      if (_name != value) 
      { 
       _name = value; 
       NotifyPropertyChanged("Name"); 
      } 
     } 
    } 

    //...All the other properties (the same way)... 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

변화하는 방법이 감소하는 것 :


이 클래스가 어떻게 보이는지 (지금 당신은 뷰 모델의 재산 "이름이"존재하지 않는, 변화하는보기를 말하고있다) 로 : 현재

public void setMovieName(Movie movie, string newName) 
    { 
     Console.WriteLine("CurrentName: " + movie.Name); 
     movie.Name = newName; //The notification is now raised automatically in the setter of the property in the movie class 
     Console.WriteLine("NewName: " + movie.Name); 
    } 
+0

하지만 http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/432/MVVM-for-Tarded-Folks-Like-Me-or-MVVM-and-What-it-Means-to -Me.aspx 그들은 ViewModel에 INotifyPropertyChanged를 두었습니까? 잘못인가? – Mech0z

+0

아니요 - 귀하의 경우에는 ViewModel * 및 * Movie 클래스에서 모두 구현해야합니다. 스레드에서 내 대답을 참조하고 설명을 요청하십시오. –

+1

viewmodel에서도이 속성이 필요할 수 있지만 속성의 속성이 아니라 실제로보기 모델에있는 속성에 대해서만 필요합니다. –

2

동영상 자체가 INotifyPropertyChanged를 구현해야한다고 생각합니다. 잘못된 개체 (viewmodel)를 통해 알립니다.

0

, 당신은 당신의 MainViewModel 인상 Name 변화에 대한 NotifyPropertyChanged 이벤트가있어. 대신 Movie 개체가 해당 속성을 바인딩 한 개체이기 때문에 Movie 인스턴스가 해당 이벤트를 발생시켜야합니다.

2

Movie 클래스에도 INotifyPropertyChanged를 구현해야합니다.

setMovieName 메서드에서 보내는 알림은 실제로 아무 것도 의미하지 않습니다. 단지 "속성"이름 일뿐입니다. "Foo"일 수도 있고 이벤트 핸들러는 "Foo"라고 말할 것입니다.

대신에 Movie 개체 자체를 업데이트해야합니다.

아마도 가장 좋은 구현은 INotifyPropertyChanged를 알리는 추상 클래스를 만든 다음 두 클래스 모두 구현해야하므로 ViewModel과 Movie 클래스를 파생시키는 것입니다.

ViewModel에서 바인딩 속성을 사용할 수 있으며 해당 ViewModel 내부에 관찰 가능한 개체 (예 : 영화)를 바인딩 할 수도 있습니다.

관련 문제