Estoy tratando de encontrar una alternativa más limpia (que sea idiomática para Scala) al tipo de cosa que se ve con el enlace de datos en el enlace de datos WPF/silverlight, es decir, implementar INotifyPropertyChanged. Primero, algunos antecedentes:propiedad idiomática cambió la notificación en scala?
En las aplicaciones .Net WPF o Silverlight, tiene el concepto de vinculación de datos bidireccional (es decir, vincula el valor de algún elemento de la interfaz de usuario a una propiedad .net del DataContext en de tal forma que los cambios en el elemento UI afecten la propiedad, y viceversa. Una forma de habilitar esto es implementar la interfaz INotifyPropertyChanged en su DataContext. Desafortunadamente, esto introduce una gran cantidad de código repetitivo para cualquier propiedad que agregue a "ModelView". . "tipo Aquí es cómo puede ser que mire en Scala:
trait IDrawable extends INotifyPropertyChanged
{
protected var drawOrder : Int = 0
def DrawOrder : Int = drawOrder
def DrawOrder_=(value : Int) {
if(drawOrder != value) {
drawOrder = value
OnPropertyChanged("DrawOrder")
}
}
protected var visible : Boolean = true
def Visible : Boolean = visible
def Visible_=(value: Boolean) = {
if(visible != value) {
visible = value
OnPropertyChanged("Visible")
}
}
def Mutate() : Unit = {
if(Visible) {
DrawOrder += 1 // Should trigger the PropertyChanged "Event" of INotifyPropertyChanged trait
}
}
}
Por razones de espacio, vamos a suponer el tipo INotifyPropertyChanged es un rasgo que gestiona una lista de las devoluciones de llamada de tipo (AnyRef, cadena) => Unidad, y que OnPropertyChanged es un método que invoca todas las devoluciones de llamada, pasando "this" como AnyRef y la cadena pasada). Esto solo sería un evento en C#.
Puede ver el problema de inmediato: eso es un montón de código repetitivo para solo dos propiedades. Siempre he querido escribir algo como esto en su lugar:
trait IDrawable
{
val Visible = new ObservableProperty[Boolean]('Visible, true)
val DrawOrder = new ObservableProperty[Int]('DrawOrder, 0)
def Mutate() : Unit = {
if(Visible) {
DrawOrder += 1 // Should trigger the PropertyChanged "Event" of ObservableProperty class
}
}
}
sé que puedo escribir fácilmente de esta manera, si ObservableProperty [T] tiene un valor =/VALUE_ métodos (este es el método que estoy usando ahora):
trait IDrawable {
// on a side note, is there some way to get a Symbol representing the Visible field
// on the following line, instead of hard-coding it in the ObservableProperty
// constructor?
val Visible = new ObservableProperty[Boolean]('Visible, true)
val DrawOrder = new ObservableProperty[Int]('DrawOrder, 0)
def Mutate() : Unit = {
if(Visible.Value) {
DrawOrder.Value += 1
}
}
}
// given this implementation of ObservableProperty[T] in my library
// note: IEvent, Event, and EventArgs are classes in my library for
// handling lists of callbacks - they work similarly to events in C#
class PropertyChangedEventArgs(val PropertyName: Symbol) extends EventArgs("")
class ObservableProperty[T](val PropertyName: Symbol, private var value: T) {
protected val propertyChanged = new Event[PropertyChangedEventArgs]
def PropertyChanged: IEvent[PropertyChangedEventArgs] = propertyChanged
def Value = value;
def Value_=(value: T) {
if(this.value != value) {
this.value = value
propertyChanged(this, new PropertyChangedEventArgs(PropertyName))
}
}
}
pero ¿hay alguna manera de poner en práctica la primera versión utilizando implícitos o alguna otra característica/idioma de Scala para hacer la función casos ObservableProperty como si fueran normales "propiedades" en Scala, sin necesidad de llamar los métodos de valor? La única otra cosa que puedo pensar es algo como esto, que es más detallado que cualquiera de las dos versiones anteriores, pero todavía es menos detallado que el original:
trait IDrawable {
private val visible = new ObservableProperty[Boolean]('Visible, false)
def Visible = visible.Value
def Visible_=(value: Boolean): Unit = { visible.Value = value }
private val drawOrder = new ObservableProperty[Int]('DrawOrder, 0)
def DrawOrder = drawOrder.Value
def DrawOrder_=(value: Int): Unit = { drawOrder.Value = value }
def Mutate() : Unit = {
if(Visible) {
DrawOrder += 1
}
}
}
Te puede interesar este artículo: http://www.ganguin.net/frp2d.pdf –
Ver también http: // stackoverflow.com/questions/1054179/functional-reactive-programming-in-scala Hasta ahora no hay ningún éxito. Desafortunadamente, esta fue una decisión de diseño pobre en Scala. – thSoft