Ich versuche eine sauberere Alternative (die zu Scala idiomatisch ist) zu der Art von Dingen zu finden, die Sie bei Datenbindung in WPF/silverlight Datenbindung sehen - das heißt, INotifyPropertyChanged zu implementieren. Zuerst einige Hintergrund:idiomatische Eigenschaft geändert Benachrichtigung in scala?
In .Net WPF oder Silverlight-Anwendungen haben Sie das Konzept der Zwei-Wege-Datenbindung (dh Bindung der Wert eines Elements der Benutzeroberfläche an eine .net-Eigenschaft des DataContext in Auf diese Weise wirken sich Änderungen am Oberflächenelement auf die Eigenschaft aus und umgekehrt. Eine Möglichkeit, dies zu aktivieren, besteht darin, die INotifyPropertyChanged-Schnittstelle in Ihrem DataContext zu implementieren. Dies führt leider zu einer großen Menge Code für jede Eigenschaft, die Sie dem "ModelView" hinzufügen . "Typ Hier ist, wie es in Scala aussehen könnte:
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
}
}
}
aus Gründen der Raum, lassen sie uns die INotifyPropertyChanged Typ nehmen ist eine Eigenschaft, die eine Liste der Rückrufe vom Typ verwaltet (AnyRef, String) => Unit, und OnPropertyChanged ist eine Methode, die all diese Callbacks aufruft und "this" als AnyRef und den übergebenen String weiterleitet. Dies wäre nur ein Ereignis in C#.
Sie können sofort das Problem sehen: das ist eine Tonne Standardcode für nur zwei Eigenschaften.
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
}
}
}
Ich weiß, dass ich es leicht schreiben kann wie diese, wenn ObservableProperty [T] hat Wert/VALUE_ = Methoden (dies ist die Methode, die ich bin mit: Ich habe immer statt, so etwas schreiben will jetzt):
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))
}
}
}
Aber ist es eine Möglichkeit, die erste Version mit implicits oder einem anderen Funktion/Idiom der Scala zu implementieren, um ObservableProperty Instanzen Funktion als wären sie normale „Eigenschaften“ in scala, ohne dass nennen zu machen die Wertmethoden? Das einzige, was ich denken kann, ist so etwas wie dieses, die als eine der beiden oben genannten Versionen ausführlicher ist, ist aber immer noch weniger ausführlich als das 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
}
}
}
Dieses Papier könnte Sie interessieren: http://www.ganguin.net/frp2d.pdf –
Siehe auch http: // stackoverflow.com/questions/1054179/funktional-reaktive-programmierung-in-scala Bisher kein Erfolg. Leider war das eine schlechte Designentscheidung in Scala. – thSoft