2011-07-24 8 views
1

私はいくつかのXAMLコードをViewModelのプロパティにバインドしようとしています。INotifyPropertyChanged 'Double' binding

<Grid Visibility="{Binding HasMovies, Converter={StaticResources VisibilityConverter}}"> 
... 
</Grid> 

私のViewModelには、このような設定です:CPで

MovieListViewModel() 
{ 
    HasMovies = CP.Connection.HasMovies; 
} 

public bool HasMovies 
     { 
      get { return MovieList != null && MovieList.Count > 0; } 
     } 

private ObservableCollection<Movie> _movies; 
     public ObservableCollection<Movie> MovieList 
     { 
      get { return _movies; } 
      set 
      { 
       _movies = value; 
       RaisePropertyChanged("MovieList"); 
       RaisePropertyChanged("HasMovies"); 
       _movies.CollectionChanged += MovieListChanged; 
      } 
     } 

     private void MovieListChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      RaisePropertyChanged("HasMovies"); 
     } 

private bool _hasMovies; 
     public bool HasMovies 
     { 
      get { return _hasMovies; } 
      set { _hasMovies = value; RaisePropertyChanged("HasMovies"); } 
     } 

のViewModelのコンストラクタで、私はHasMoviesリンクを設定します

私は間違って何をしていますか?このバインディングを変更して現在の状態がCP.Connection.HasMoviesに反映されるようにするにはどうすればよいですか?

答えて

3

ViewModelで直接オブジェクトを公開し、そのオブジェクトを直接バインドします(その値はコピーされていないので、今度はPropertyChangedイベントにサブスクライブし、変更するたびにHasMoviesを新しい値に設定します)。あなたのソースオブジェクトに。

あなたは、コレクションの内容を変更すると、すべての

CP.Connection.PropertyChanged += (s,e) => 
    { 
     if (e.PropertyName = "HasMovies") this.HasMovies = CP.Connection.HasMovies; 
    }; 
+0

私が探しているもののように見えますが、私はかなりの数の場所でこのプロパティを使用するので、オブジェクトに直接結合する最初のアイデアは、良いアイデアのように聞こえます。このバインディングをXAMLで行う方法の例がありますか? –

+0

PropertyChangedイベントはコレクションにアイテムを追加したり削除したりするときに呼び出されません**ので、それはひどいばかげた解決策です。 –

+0

@willmel:バインディングのためのコードのようなパスを使うことができます。接続オブジェクトを 'Connection'というプロパティとして公開すると、バインディングは' {Connection Connection.HasMovies、Converter = ...} '。 –

1

まず、あなたのMovieListプロパティとしてコレクション型のセッターは、(すなわち。項目を追加/削除)と呼ばれるないです。

これは、MovieListプロパティのすべてのセッターコードが無意味であることを意味します。

第2に、非常にばかげたコードです。はるかに良い解決策は、NotifyPropertyWeaverを使用することです。次に、あなたのコードはのviewmodelで、次のようになります。

[DependsOn("MovieList")] 
public bool HasMovies 
{ 
    get { return MovieList != null && MovieList.Count > 0; } 
} 

public ObservableCollection<Movie> MovieList 
{ 
    get; 
    private set; 
} 

また、あなたがMovieListプロパティに本当に初めて(バッキングプロパティを持っていない理由は、初期化するときて、CollectionChangedイベントのリスナーを追加する必要があります本当に理由はありません!)、イベントハンドラでRaisePropertyChanged( "HasMovies")を呼び出します。

例:

public class CP : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public CP() 
    { 
     MovieList = new ObservableCollection<Movie>(); 
     MovieList.CollectionChanged += MovieListChanged; 
    } 

    public bool HasMovies 
    { 
     get { return MovieList != null && MovieList.Count > 0; } 
    } 

    public ObservableCollection<Movie> MovieList 
    { 
     get; 
     private set; 
    } 

    private void MovieListChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     RaisePropertyChanged("HasMovies"); 
    } 

    private void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
+0

あなたはコレクションのセッターを見ましたか?そこにハンドラがCollectionChangedイベントに接続されている、それは動作する必要があります... –

+0

彼はバッキングフィールドを使用していると考えて、言ったセッターが呼び出されることはほとんどありません。また、RaisePropertyChanged( "HasMovies");セッターの中では何も役に立つことはありません。いずれにしても、NotifyProperWeaverを使用するのが最も美しい方法です。 –

+0

@Claus。 [DependsOn( "MovieList")]は実際にNPWが​​その依存関係を導き出すので冗長です – Simon