J'essaie de trouver une alternative plus propre (idiomatique à Scala) au type de chose que vous voyez avec la liaison de données dans la liaison de données WPF/silverlight - c'est-à-dire l'implémentation de INotifyPropertyChanged. En arrière-plan:La propriété idiomatique a changé de notification dans scala?
Dans .NET WPF ou applications Silverlight, vous avez le concept de liaison de données bidirectionnelle (c'est-à-dire, la liaison de la valeur d'un élément de l'interface utilisateur à une propriété .net du DataContext dans Une façon d'activer l'interface INotifyPropertyChanged dans votre DataContext, malheureusement, cela introduit beaucoup de code standard pour toutes les propriétés que vous ajoutez au "ModelView". . «type Voici comment cela pourrait ressembler à 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
}
}
}
Pour des raisons d'espace, supposons que le type INotifyPropertyChanged est un trait qui gère une liste des callbacks de type (AnyRef, String) => Unit, et que OnPropertyChanged est une méthode qui invoque tous ces callbacks, en passant "this" comme AnyRef, et la chaîne passée. Ce serait juste un événement en C#.
Vous pouvez immédiatement voir le problème: c'est une tonne de code standard pour deux propriétés. J'ai toujours voulu écrire quelque chose comme ceci:
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
}
}
}
Je sais que je peux facilement l'écrire comme ça, si ObservableProperty [T] a une valeur/VALUE_ = méthodes (ce qui est la méthode que je utilise maintenant):
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))
}
}
}
Mais est-il possible de mettre en œuvre la première version en utilisant implicits ou une autre caractéristique/idiome de Scala pour faire fonctionner les instances de ObservableProperty comme si elles étaient des « propriétés » régulières dans scala, sans avoir besoin d'appeler les méthodes de la valeur? La seule autre chose que je peux penser à quelque chose comme ça, ce qui est plus prolixe que l'une des deux versions ci-dessus, mais il est encore moins prolixe que l'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
}
}
}
Ce document peut vous intéresser: http://www.ganguin.net/frp2d.pdf –
Voir aussi http: // stackoverflow.com/questions/1054179/functional-reactive-programming-in-scala Aucun succès pour l'instant. Malheureusement, ce fut une mauvaise décision de conception à Scala. – thSoft