2011-08-29 187 views
2

我無法讓我的用戶界面更新兩個Listboxes,以在我的ViewModel更改時正確更新。RaisePropertyChanged不更新UI

首先,頁面背後的基本邏輯:

電影是具有標題的對象,以及各種MovieDetails。有些MovieDetail是比別人不同,因爲它們是詳細這是說他們是更重要的一個華而不實的方式。 我使用兩個ListBoxes分離這些MovieDetails堆疊ListBoxes,一個用於「詳細」,一個用於「NotDetailed」 如果電影沒有「詳細」屬性,相應列表經由BooleanToVisibilityConverter(反之亦然隱藏)

當我瀏覽網頁,我設置了Movie頁面對應,應該RaisePropertyChanged提醒AllMoviesDetailObservableCollection,它應該重新得到Movies.MovieDetailFetchedList。 從那裏,AllMoviesDetail將提醒兩個ObservableCollections (Detailed, NotDetailed)他們應該重新get

實際上,NotDetailedMovieDetailsDetailedMovieDetails上的RaisePropertyChanged似乎也沒有做任何事情。 (和相應的HasNotDetailedMovieDetails, Has...

然而,如果我向列表中添加更多項目,CollectionChanged事件似乎會觸發並重新激活列表,那麼工作是什麼。我還通過在代碼第一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

全部財產干將(除AllMoviesDetail)實例化ObservableCollections已經 return語句之所以能夠做到這一點。由於只有第一個被執行,所以這些值沒有被賦值,並且PropertyChanged事件沒有被分割。

+0

是否有2個語句可以留給不同的代碼執行?我應該如何處理這個事情,因爲在它們實際工作之前對象是通過(通過'NavigationContext綁定)訪問的? –

+1

@willmel - 返回語句將在該點結束執行。通常的模式不是在「get」中計算,而是在中心點進行計算,然後提高適當的屬性更改事件。 –

+0

感謝您的迴應。我明白,getter變成setter並沒有什麼意義 - 但是如何重寫它以便'Binding'在「Movie」對象被設置之前正常工作?即如果我正在根據OnNavigatedTo中的QueryString設置我的電影對象,則UI已經被處理並且綁定已經發生(對於無效的值,因爲尚未設置電影)。謝謝..你的迴應非常感謝。 –