2009-03-18 11 views
32

tengo una clase con una propiedad indexador, con una cadena de clave:PropertyChanged de la propiedad indexador

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

    ... 
} 

que se unen a una instancia de esta clase en WPF, usando indexador notación:

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

Eso funciona bien, pero quiero plantear un evento PropertyChanged cuando cambia uno de los valores del indexador. 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?

Respuesta

45

De acuerdo con this blog entry, debe 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 aspecto código como:

public class IndexerProvider : INotifyPropertyChanged { 

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

Por lo menos hace el intento 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.

+0

Eso funciona genial. Es extraño que extrañara ese blogpost en mis búsquedas de Google. – Inferis

+1

Esta solución funciona muy bien, pero tiene una limitación molesta: no puede especificar que el valor haya cambiado solo para una clave ... Por lo tanto, si tiene enlaces en muchas teclas, todas serán actualizadas –

+0

Unos años más tarde, ahora ahí está la palabra clave 'nameof'. Lo uso para todas mis llamadas 'FirePropertyChange', pero ¿puedes' nombrar' el indexador de alguna manera? – Flynn1179

5

En realidad, creo que establecer el atributo IndexerName en "Artículo" 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. Así que el código podría ser algo como esto:

public class IndexerProvider : INotifyPropertyChanged { 

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

Una vez que se establece el nombre de controlador paso a paso a lo que quieras, a continuación, puede usarlo en caso FirePropertyChanged.

15

Adicionalmente, puede utilizar

FirePropertyChanged ("Item[IndexerKeyThingy]"); 

Para notificar únicamente los controles enlazados a IndexerKeyThingy en su indexador.

+0

+1 Es útil saber que puede elevarlo por entrada de diccionario – abbottdev

+5

¿Alguien ha conseguido que esto funcione correctamente? No está funcionando para mí. Solo "Elemento []" parece desencadenar actualizaciones. –

+2

Funciona bien en Silverlight 4/5, pero en WPF 4.6.2 no funciona en absoluto. Todavía tiene que usar el elemento []. – AqD

5

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 popular methods de 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 

Varios otherposts han utilizado Binding.IndexerName para evitar la cadena literal "Item[]", lo cual 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 un valor constante sugiere que WPF se espera que para ser el nombre pasado en el caso PropertyChanged, y, aunque no le importa lo que la propiedad real se llama (que yo no determinó a mi satisfacción de una manera u otra), evitar el uso de [IndexerName] mantendría la coherencia.

Cuestiones relacionadas