2011-08-29 9 views
2

ViewModel이 변경 될 때 UI를 올바르게 업데이트하기 위해 두 개의 목록 상자를 업데이트하는 데 문제가 있습니다.RaisePropertyChanged가 UI를 업데이트하지 않습니다.

첫 페이지 뒤의 기본 논리는 :

영화 제목을 가진 객체, 그리고 MovieDetails의 다양한입니다. MovieDetail자세한 내용은입니다. 더 중요한 것을 말하는 영광스러운 방법입니다. 나는 두 ListBoxes 영화가있는 경우이 MovieDetails으로는 'NotDetailed'에 대한ListBoxes, '상세'에 대한 하나 하나를 쌓아 구분하는 데 사용할 없음 '상세', 해당 목록은 BooleanToVisibilityConverter (반대의 경우도 마찬가지 통해 숨겨진되는 속성

나는 페이지로 이동)

, 나는 페이지에 해당하는 Movie을 설정하고 그것을 RaisePropertyChangedMovies.MovieDetailFetchedList을 다시 얻을해야 AllMoviesDetail ObservableCollection을 경고해야한다. 거기에서 AllMoviesDetail은 두 ObservableCollections (Detailed, NotDetailed)에 다시 get이어야한다고 알립니다.

실제로 RaisePropertyChanged (NotDetailedMovieDetails 또는 DetailedMovieDetails)은 아무 것도하지 않는 것으로 보입니다. (그리고 해당 해당 HasNotDetailedMovieDetails, Has...)

그러나 목록에 더 많은 항목을 추가하면 어떻게 작동합니까, CollectionChanged 이벤트를 발생시키고 목록을 다시 활성화 할 것입니다. 또한 (AllMoviesDetail 제외) var temp = DetailedMoviesDetail;

public class MoviesDetailViewModel : ViewModelBase 
{ 
    #region Property Names 

    public const string MoviePropertyString = "Movie"; 
    public const string AllMoviesDetailPropertyString = "AllMoviesDetail"; 
    public const string DetailedMoviesDetailPropertyString = "DetailedMoviesDetail"; 
    public const string NotDetailedMoviesDetailPropertyString = "NotDetailedMoviesDetail"; 
    public const string HasNotDetailedMoviesDetailPropertyString = "HasNotDetailedMoviesDetail"; 
    public const string HasDetailedMoviesDetailPropertyString = "HasDetailedMoviesDetail"; 
    public const string NotDetailedHeaderPropertyString = "NotDetailedHeader"; 

    #endregion 


    public MoviesDetailViewModel() 
    { 
     if (IsInDesignMode) 
     { 
      Movie = DesignDataStore.MovieList[0]; 
      Movie.Category = Category.DDA; 
     } 
    } 

    private Movie _Movie; 

    /// <summary> 
    /// The Movie for which to browse MoviesDetail. It is expected when setting this property, that MoviesDetail for it have been downloaded previously. 
    /// </summary> 
    /// <remarks>The 'Master' property for this ViewModel. All properties are Dependent on this and the underlying property MoviesDetailList</remarks> 
    /// <seealso cref="MovieDetailFetchedList"/> 
    public Movie Movie 
    { 
     get { return _Movie; } 
     set 
     { 
      if (_Movie != value) 
      { 
       if (_Movie != null) 
        _Movie.MovieDetailFetchedList.CollectionChanged -= MoviesDetailListChanged; 


       _Movie = value; 

       RaisePropertyChanged(MoviePropertyString); 
       RaisePropertyChanged(StatementPeriodAvailablePropertyString); 
       RaisePropertyChanged(NotDetailedMoviesDetailPropertyString); 
       Movie.MovieDetailFetchedList.CollectionChanged += MoviesDetailListChanged; 

       RaisePropertyChanged(AllMoviesDetailPropertyString); 

       RaisePropertyChanged(DetailedMoviesDetailPropertyString); 

       RaisePropertyChanged(NotDetailedHeaderPropertyString); 
      } 
     } 
    } 

    private void MoviesDetailListChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      foreach (var item in e.NewItems) 
      { 
       if (((MovieDetail) item).IsDetailed()) 
        DetailedMoviesDetail.Add(item as MovieDetail); 
       else 
        NotDetailedMoviesDetail.Add(item as MovieDetail); 
      } 
     } 
     else 
     { 
      RaisePropertyChanged(AllMoviesDetailPropertyString); 
      RaisePropertyChanged(DetailedMoviesDetailPropertyString); 
      RaisePropertyChanged(NotDetailedMoviesDetailPropertyString); 
     } 
    } 




    #endregion 

    private MovieDetailFetchedList _allMoviesDetail; 
    public MovieDetailFetchedList AllMoviesDetail 
    { 
     get 
     { 
      if (Movie == null) 
       return new MovieDetailFetchedList(); 

      return _allMoviesDetail ?? (AllMoviesDetail = Movie.MovieDetailFetchedList); 
     } 
     set 
     { 
      if (_allMoviesDetail != value) 
      { 
       if (_allMoviesDetail != null) 
        _allMoviesDetail.CollectionChanged -= MoviesDetailListChanged; 
       _allMoviesDetail = value; 
       _allMoviesDetail.CollectionChanged += MoviesDetailListChanged; 

       RaisePropertyChanged(AllMoviesDetailPropertyString); 
       //force update 
       DetailedMoviesDetail = NotDetailedMoviesDetail = null; 
       RaisePropertyChanged(DetailedMoviesDetailPropertyString); 
       RaisePropertyChanged(HasDetailedMoviesDetailPropertyString); 
       RaisePropertyChanged(NotDetailedMoviesDetailPropertyString); 
       RaisePropertyChanged(HasNotDetailedMoviesDetailPropertyString); 
      } 

     } 
    } 

    public bool HasNotDetailedMoviesDetail { get { return NotDetailedMoviesDetail != null && NotDetailedMoviesDetail.Count > 0; } } 



    private ObservableCollection<MovieDetail> _notDetailedMoviesDetail; 
    public ObservableCollection<MovieDetail> NotDetailedMoviesDetail 
    { 
     get 
     { 
      if (Movie == null) return new ObservableCollection<MovieDetail>(); 

      return AllMoviesDetail; 
       return _notDetailedMoviesDetail ?? //make sure RaisePropertyChanged happens by using property setter 
       (NotDetailedMoviesDetail = AllMoviesDetail.Where(mem => !mem.IsDetailed()).ToObservableCollection()); 
     } 
     set 
     { 
      _notDetailedMoviesDetail = value; 
      RaisePropertyChanged(NotDetailedMoviesDetailPropertyString); 
      RaisePropertyChanged(HasNotDetailedMoviesDetailPropertyString); 
     } 
    } 

    public bool HasDetailedMoviesDetail 
    { get { return DetailedMoviesDetail != null && DetailedMoviesDetail.Count > 0; } } 

    private ObservableCollection<MovieDetail> _DetailedMoviesDetail; 
    public ObservableCollection<MovieDetail> DetailedMoviesDetail 
    { 
     get 
     { 
      if (Movie == null) return new ObservableCollection<MovieDetail>(); 

      return AllMoviesDetail; 
      return _DetailedMoviesDetail ?? //make sure RaisePropertyChanged happens by using property setter 
      (DetailedMoviesDetail = AllMoviesDetail.Where(mem => mem.IsDetailed()).ToObservableCollection()); 
     } 
     set 
     { 
      _DetailedMoviesDetail = value; 
      RaisePropertyChanged(DetailedMoviesDetailPropertyString); 
      RaisePropertyChanged(HasDetailedMoviesDetailPropertyString); 
     } 
    } 


    private string _DetailedHeader; 
    public string DetailedHeader 
    { 
     get { return _DetailedHeader ?? (_DetailedHeader = AppResources.in_available); } 
     set { _DetailedHeader = value; } 
    } 

    public string NotDetailedHeader 
    { 
     get { return (Movie != null && Movie.Category == Category.DRAMA) ? AppResources.Movie_MoviesDetail : AppResources.not_in_available; } 
    } 
} 
+3

자세한 질문 주셔서 감사합니다. 그래도 문제를 재현하는 작은 코드 샘플을 제공 할 수 있다면 훨씬 더 도움이 될 것입니다. 그리고 대부분의 경우, 최소한의 예를 준비하는 과정에서 문제를 직접 해결하는 데 필요한 통찰력을 얻을 수 있습니다. – Dathan

+0

또한 INotifyPropertyChanged를 구현하는 클래스를 나타내는 코드를 포함하십시오. –

답변

4

재산 게터의 모든 첫 번째 코드에 반환 문을 ObservableCollections을 한 인스턴스화하여이 작업을 수행 할 수 있었다. 첫 번째 만 실행되기 때문에 값이 할당되지 않고 PropertyChanged 이벤트가 트랩되지 않습니다.

+0

다른 코드를 실행할 수있는 문을 2 개 가지고 있으면 문제가됩니까? 그들이 실제로 작동하기 전에 객체가 (NavigationContext를 통해 바인딩을 통해) 액세스되는 것을 어떻게 처리해야합니까? –

+1

@willmel - return 문은 그 시점에서 실행을 종료합니다. 일반적인 패턴은'get'에서 계산하는 것이 아니라 중심점에서 계산 한 다음 적절한 속성 변경 이벤트를 발생시키는 것입니다. –

+0

응답 해 주셔서 감사합니다. getter가 설정자가되는 것이 실제로 의미가 없다는 것을 이해합니다. 그러나'Movie' 객체가 설정되기 전에'Binding'이 제대로 작동하도록 어떻게 다시 작성하겠습니까? 즉, 'OnNavigatedTo'의 QueryString을 기반으로 My Movie 객체를 설정하면 UI가 이미 처리되고 바인딩이 이미 발생했습니다 (무비 값은 아직 설정되지 않았으므로). 감사합니다 ... 귀하의 답변을 많이 주시면 감사하겠습니다. –

관련 문제