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
Commandis being called, but the result is not what you'd expected.For testing purposes try
Note the
CommandSyncinstead ofEventValueCommand. No matter how you change the score, a msgbox will pop up.You could also keep the
EventValueCommandand do the same in the
updatefunGetting 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.Textvalue.As you've noticed there's no (pure) way to bring the
TextBox.Textvalue into theupdatefun 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 -> Scoreand use the option value to handle SetX events in theupdatefun.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.ScoreXchanged toScoreXText="{Binding Score.ScoreA, Mode=OneWay}"changed toText="{Binding ScoreA, UpdateSourceTrigger=PropertyChanged}"Interaction.Trigger