PropertyChanged para la propiedad del indexador


Tengo una clase con una propiedad indexer, con una clave de cadena:

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

    ...
}

Me enlazo a una instancia de esta clase en WPF, usando notación indexadora:

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

Eso funciona bien, pero quiero generar un evento PropertyChanged cuando uno de los valores del indexador cambia. Traté de subirlo con un nombre de propiedad de "[keyname] " (es decir, incluyendo [] alrededor del nombre de la clave), pero eso no parece funcionar. No recibo errores de enlace en mi ventana de salida en absoluto.

No puedo usar CollectionChangedEvent, porque el índice no está basado en enteros. Y técnicamente, el objeto no es una colección de todos modos.

Puedo hacer esto, y así, ¿cómo?

Author: Inferis, 2009-03-18

4 answers

De acuerdo con esta entrada del blog, tienes que usar "Item[]". Item es el nombre de la propiedad generada por el compilador cuando se utiliza un indexador.

Si desea ser explícito, puede decorar la propiedad indexer con un atributo IndexerName.

Eso haría que el código se vea como:

public class IndexerProvider : INotifyPropertyChanged {

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

Al menos hace que la intención sea más clara. Sin embargo, no sugiero que cambie el nombre del indexador, si su amigo encontró la cadena "Item[]" codificada, probablemente significa que WPF no sería capaz de tratar con un nombre de indexador diferente.

 45
Author: Jb Evain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 13:57:24

Además, puede usar

FirePropertyChanged ("Item[IndexerKeyThingy]");

Para notificar solo a los controles vinculados a IndexerKeyThingy en su indexador.

 15
Author: ghord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 09:29:04

En realidad, creo que establecer el atributo IndexerName a "Item" es redundante. El atributo IndexerName está diseñado específicamente para cambiar el nombre de un índice, si desea darle un nombre diferente a su elemento de colección. Así que su código podría verse algo como esto:

public class IndexerProvider : INotifyPropertyChanged {

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

Una vez que establezca el nombre del indexador a lo que desee, puede usarlo en el evento FirePropertyChanged.

 5
Author: dimondwoof,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-11 17:16:54

Hay al menos un par de advertencias adicionales cuando se trata de INotifyPropertyChang(ed/ing) e indexadores.

La primera es que la mayoría de los métodos populares para evitar cadenas de nombres de propiedades mágicas son ineficaces. La cadena creada por el [CallerMemberName] al atributo le falta el '[] ' al final, y las expresiones de los miembros lambda tienen problemas para expresar el concepto.

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

Varias otros puestos han utilizado Binding.IndexerName a evite la cadena literal "Item[]", que es razonable, pero plantea el segundo problema potencial. Una investigación del desmontaje de partes relacionadas de WPF reveló el siguiente segmento en 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[]";
  }

El uso repetido de "Item[]" como un valor constante sugiere que WPF espera que sea el nombre pasado en el evento PropertyChanged, e incluso si no le importa cómo se llame la propiedad real (lo que no determiné a mi satisfacción de una manera o la otros), evitar el uso de [IndexerName] mantendría la coherencia.

 5
Author: Andrew Elford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-27 19:30:46