2009-03-18 13 views
32

インデクサープロパティに対してのPropertyChangedそれは正常に動作しますが、インデクサー値の1つが変更されたときにPropertyChangedイベントを発生させたいとします。私は "[keyname]"というプロパティ名(キーの名前の周りに[]を含む)でそれを呼び出そうとしましたが、それはうまくいかないようです。私は出力ウィンドウに綴じ誤差が全くない。は、キーの文字列で、私は、インデクサプロパティを持つクラスを持っている

インデックスが整数ベースでないため、CollectionChangedEventを使用できません。そして技術的には、オブジェクトはとにかくコレクションではありません。

どうすればいいですか?

答えて

45

this blog entryによれば、"Item[]"を使用する必要があります。項目は、インデクサーを使用するときにコンパイラーによって生成されるプロパティーの名前です。

明示的にしたい場合は、IndexerName属性でインデクサープロパティを修飾することができます。以下のようなコードを見てになるだろう

public class IndexerProvider : INotifyPropertyChanged { 

    [IndexerName ("Item")] 
    public object this [string key] { 
     get { 
      return ...; 
     } 
     set { 
      ... = value; 
      FirePropertyChanged ("Item[]"); 
     } 
    } 
} 

は、少なくとも、それは意図がより明確になります。インデクサー名を変更することはお勧めしません。文字列"Item[]"がハードコードされていれば、おそらくWPFは別のインデクサー名を扱うことができません。

+0

それは素晴らしい動作します。奇妙なことに、私は自分のGoogle検索でそのブログポストを見逃してしまった。 – Inferis

+1

このソリューションは素晴らしいですが、厄介な制限があります:1つのキーに対してのみ値が変更されるように指定することはできません...したがって、多くのキーにバインディングがある場合、それらはすべてリフレッシュされます –

+0

数年後'nameof'というキーワードがあります。すべての私の 'FirePropertyChange'呼び出しにこれを使用しますが、インデクサーを' nameof'することはできますか? – Flynn1179

5

実際、私はIndexerName属性を "Item"に設定するのは冗長だと考えています。 IndexerName属性は、コレクションアイテムに別の名前を付ける場合に、インデックスの名前を変更するように特別に設計されています。あなたが好きにインデクサ名を設定すると

public class IndexerProvider : INotifyPropertyChanged { 

    [IndexerName("myIndexItem")] 
    public object this [string key] { 
     get { 
      return ...; 
     } 
     set { 
      ... = value; 
      FirePropertyChanged ("myIndexItem[]"); 
     } 
    } 
} 

は、あなたがしてFirePropertyChangedイベントでそれを使用することができますので、あなたのコードは次のようなものを見ることができます。

15

Additionaly、あなたはあなたのインデクサにIndexerKeyThingyにバインドされたコントロールだけを通知するに

FirePropertyChanged ("Item[IndexerKeyThingy]"); 

を使用することができます。

+0

+1辞書のエントリごとにそれを上げることができることを知っておくと便利です – abbottdev

+5

誰もこれをうまく動作させることに成功しましたか?それは私のために働いていません。 「アイテム[]」だけが更新を引き起こすようです。 –

+2

Silverlight 4/5ではうまく動作しますが、WPF 4.6.2ではまったく動作しません。アイテム[]を使用する必要があります。 – AqD

5

INotifyPropertyChang(ed/ing)とインデクサを扱う際には、少なくとも2つの警告があります。

最初に、魔法のプロパティ名文字列を避けるのはpopular methodsのほとんどが効果がないということです。 [CallerMemberName]属性によって作成された文字列の最後に '[]'がありません。また、lambdaメンバ式には、その概念を表現する上で問題があります。 postsotherいくつかの

() => this[] //Is invalid 
() => this[i] //Is a method call expression on get_Item(TIndex i) 
() => this //Is a constant expression on the base object 

は合理的であるが、2番目の潜在的な問題を提起"Item[]"文字列リテラルを、避けるためにBinding.IndexerNameを使用しています。 WPFの関連部分の解体を調べると、PropertyPath.ResolvePathPartsで次のセグメントが表示されました。

if (this._arySVI[i].type == SourceValueType.Indexer) 
    { 
    IndexerParameterInfo[] array = this.ResolveIndexerParams(this._arySVI[i].paramList, obj, throwOnError); 
    this._earlyBoundPathParts[i] = array; 
    this._arySVI[i].propertyName = "Item[]"; 
    } 

一定の値として"Item[]"の繰り返し使用は、WPFは、それが(実際のプロパティは、いわゆる気にしない場合でも、それはPropertyChangedイベントに渡された名前であることを期待して、されていることを示唆しているI私の満足感を一方的に、あるいは他の方法で判断しなかった)、[IndexerName]の使用を避けて、一貫性を維持するだろう。

関連する問題