c# - PropertyChanged para propiedad del indexador
wpf data-binding (4)
Adicionalmente, puedes usar
FirePropertyChanged ("Item[IndexerKeyThingy]");
Para notificar solo los controles vinculados a IndexerKeyThingy en su indexador.
Tengo una clase con una propiedad de indexador, con una clave de cadena:
public class IndexerProvider {
public object this[string key] {
get
{
return ...
}
set
{
...
}
}
...
}
Me enlace a una instancia de esta clase en WPF, usando la notación del indexador:
<TextBox Text="{Binding [IndexerKeyThingy]}">
Eso funciona bien, pero quiero plantear un evento PropertyChanged
cuando cambia uno de los valores del indizador. Intenté subirlo con un nombre de propiedad de "[keyname]" (es decir, que incluye [] alrededor del nombre de la tecla), pero parece que no funciona. No obtengo errores vinculantes en mi ventana de salida en absoluto.
No puedo usar CollectionChangedEvent, porque el índice no está basado en un entero. Y técnicamente, el objeto no es una colección de todos modos.
¿Puedo hacer esto, y entonces, cómo?
De acuerdo con esta entrada del blog , debes usar "Item[]"
. Item es el nombre de la propiedad generada por el compilador al usar un indexador.
Si quiere ser explícito, puede decorar la propiedad del indexador con un atributo IndexerName .
Eso haría que el código se vea así:
public class IndexerProvider : INotifyPropertyChanged {
[IndexerName ("Item")]
public object this [string key] {
get {
return ...;
}
set {
... = value;
FirePropertyChanged ("Item[]");
}
}
}
Al menos hace que el intento sea más claro. Sin embargo, no sugiero que cambie el nombre del indizador, si su amigo encontró la cadena "Item[]"
codificada, probablemente signifique que WPF no podría tratar con un nombre de indizador diferente.
En realidad, creo que establecer el atributo IndexerName en "Item" es redundante. El atributo IndexerName está específicamente diseñado para cambiar el nombre de un índice, si desea darle un nombre diferente a su elemento de colección. Entonces su código podría verse más o menos así:
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 en lo que desee, puede usarlo en el evento FirePropertyChanged.
Hay al menos un par de advertencias adicionales al tratar con INotifyPropertyChang (ed / ing) y los indexadores.
La primera es que la mayoría de los métodos populares para evitar cadenas de nombres de propiedades mágicas son ineficaces. A la cadena creada por el atributo [CallerMemberName]
le falta el ''[]'' al final, y las expresiones de los miembros lambda tienen problemas para expresar el concepto en absoluto.
() => 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 other posts han utilizado Binding.IndexerName
para evitar la cadena literal "Item[]"
, que es razonable, pero plantea el segundo problema potencial. Una investigación de la disgregación de partes relacionadas de WPF apareció en 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 valor constante sugiere que WPF espera que ese sea el nombre pasado en el evento PropertyChanged, y, aunque no le importe a qué se llama la propiedad real (que no lo hice) determinar a mi satisfacción de una manera u otra), evitar el uso de [IndexerName]
mantendría la coherencia.