I'd like to bind to a WPF TextBox in an MVVM F# application built using FsXaml and FSharp.ViewModule. I added a command called "SetA" to the application described here, and attempted to bind to it with the following XAML:
<TextBox Text="{Binding Score.ScoreA, Mode=OneWay}" FontFamily="Lucida Console">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<fsx:EventToCommand Command="{Binding SetA}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
The TextBox is correctly populated from the ScoreA property, but the SetA command is not called when I type a new value in the TextBox. I'm comfortable with F#, but this is my first WPF MVVM application, so I'm not sure what I'm doing wrong. How do I trigger my SetA handler when the user changes the text value?
This is my ViewModel:
type MainViewModel(controller : Score -> ScoringEvent -> Score) as self =
inherit EventViewModelBase<ScoringEvent>()
let score = self.Factory.Backing(<@ self.Score @>, Score.zero)
let eventHandler ev =
score.Value <- controller score.Value ev
do
self.EventStream
|> Observable.add eventHandler
member this.IncA = this.Factory.EventValueCommand(IncA)
member this.DecA = this.Factory.EventValueCommandChecked(DecA, (fun _ -> this.Score.ScoreA > 0), [ <@@ this.Score @@> ])
member this.IncB = this.Factory.EventValueCommand(IncB)
member this.DecB = this.Factory.EventValueCommandChecked(DecB, (fun _ -> this.Score.ScoreB > 0), [ <@@ this.Score @@> ])
member this.NewGame = this.Factory.EventValueCommand(New)
member this.SetA = this.Factory.EventValueCommand(SetA)
member __.Score = score.Value
I only added the one line that defines SetA.
Most likely the
Command
is being called, but the result is not what you'd expected.For testing purposes try
Note the
CommandSync
instead ofEventValueCommand
. No matter how you change the score, a msgbox will pop up.You could also keep the
EventValueCommand
and do the same in the
update
funGetting back to the not what you'd expected part, I assume you want the score in the scoreboard to update, when you change the
TextBox.Text
value.As you've noticed there's no (pure) way to bring the
TextBox.Text
value into theupdate
fun using the currentcontroller
. Due to the fact that the SetX behaviour isn't fix, unlike in the case of the IncX, DecX or New events.Options:
You could change the signature of the controller to
Score -> ScoringEvent -> string option -> Score
and use the option value to handle SetX events in theupdate
fun.You could handle everything in the
ViewModel
. The immutable nature of the record forces the use of aOneWay Binding
. I would keep it immutable, but you can (de)compose everything in the ViewModel.Try
ViewModel
XAML
Notes
Score.ScoreX
changed toScoreX
Text="{Binding Score.ScoreA, Mode=OneWay}"
changed toText="{Binding ScoreA, UpdateSourceTrigger=PropertyChanged}"
Interaction.Trigger