PropertyChanged pour indexer propriété

j'ai une classe avec une propriété d'indexeur, avec une clé string:

public class IndexerProvider {
    public object this[string key] {
        get
        {
            return ...
        }
        set
        {
            ...
        }
    }

    ...
}

je me lie à une instance de cette classe dans WPF, en utilisant la notation de l'indexeur:

<TextBox Text="{Binding [IndexerKeyThingy]}">

ça marche très bien, mais je veux soulever un événement PropertyChanged quand une des valeurs de l'indexeur change. J'ai essayé de l'élever avec un nom de propriété de "[keyname] " (i.e. y compris [] autour du nom de la clé), mais cela ne semble pas fonctionner. Je ne reçois pas d'erreurs de liaison dans mon de la fenêtre de sortie que ce soit.

Je ne peux pas utiliser CollectionChangedEvent, parce que l'index n'est pas basé sur des entiers. Et techniquement, l'objet n'est pas une collection de toute façon.

puis-je faire ceci, et donc, comment?

33
demandé sur Inferis 2009-03-18 13:17:38

4 réponses

selon cette entrée de blog , vous devez utiliser "Item[]" . Élément étant le nom de la propriété généré par le compilateur lors de l'utilisation d'un indexeur.

si vous voulez être explicite, vous pouvez décorer la propriété indexer avec un attribut nom D'index .

qui ferait ressembler le code à:

public class IndexerProvider : INotifyPropertyChanged {

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

Au moins il fait l'intention plus claire. Je ne le conseille pas vous changez le nom de l'indexeur cependant, si votre ami trouve la chaîne "Item[]" codée en dur, cela signifie probablement que WPF ne serait pas en mesure de traiter avec un nom d'indexeur différent.

45
répondu Jb Evain 2009-03-18 13:57:24

de plus, vous pouvez utiliser

FirePropertyChanged ("Item[IndexerKeyThingy]");

pour notifier uniquement les contrôles liés à IndexerKeyThingy sur votre indexeur.

15
répondu ghord 2011-08-11 09:29:04

en fait, je pense que définir L'attribut IndexerName à" Item " est redondant. L'attribut IndexerName est spécifiquement conçu pour renommer un index, si vous voulez donner son élément de collection un nom différent. Donc votre code pourrait ressembler à quelque chose comme ceci:

public class IndexerProvider : INotifyPropertyChanged {

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

une fois que vous avez défini le nom de l'indexeur à ce que vous voulez, vous pouvez l'utiliser dans L'événement FirePropertyChanged.

5
répondu dimondwoof 2010-07-11 17:16:54

il y a au moins quelques mises en garde supplémentaires lorsqu'il s'agit de L'INotifyPropertyChang(ed/ing) et des indexeurs.

La première est que la plupart des méthodes populaires d'éviter de magie nom de la propriété chaînes sont inefficaces. La chaîne créée par l'attribut [CallerMemberName] manque l'attribut" [] " à la fin, et les expressions membres lambda ont des problèmes pour exprimer le concept.

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

Plusieurs autres posts ont utilisé Binding.IndexerName pour éviter la chaîne littérale "Item[]" , ce qui est raisonnable, mais soulève le deuxième problème potentiel. Une enquête sur la dissemblance de parties apparentées de WPF a révélé le segment suivant dans 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[]";
  }

l'utilisation répétée de "Item[]" comme valeur constante suggère que WPF attend cela pour être le nom passé dans L'événement PropertyChanged, et, même si elle ne se soucie pas de ce que la propriété réelle est appelée (que je n'ai pas déterminé à ma satisfaction d'une manière ou d'une autre), en évitant l'utilisation de [IndexerName] maintiendrait la cohérence.

5
répondu Andrew Elford 2014-03-27 19:30:46