我想绑定(bind)到使用 FsXaml 和 FSharp.ViewModule 构建的 MVVM F# 应用程序中的 WPF TextBox。我向描述的应用程序添加了一个名为“SetA”的命令 here ,并尝试使用以下 XAML 绑定(bind)到它:
<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>
TextBox 是从 ScoreA 属性正确填充的,但是当我在 TextBox 中键入新值时,不会调用 SetA 命令。我对 F# 很满意,但这是我的第一个 WPF MVVM 应用程序,所以我不确定我做错了什么。当用户更改文本值时,如何触发我的 SetA 处理程序?
这是我的 View 模型:
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
我只添加了定义 SetA 的一行。
最佳答案
很可能正在调用 Command
,但结果不是您所期望的。
出于测试目的尝试
member this.SetA =
this.Factory.CommandSync(
fun _ -> System.Windows.MessageBox.Show("TextChanged","RoutedEv") |> ignore)
请注意 CommandSync
而不是 EventValueCommand
。无论您如何更改分数,都会弹出一个消息框。
您还可以保留 EventValueCommand
member this.SetA = this.Factory.EventValueCommand(SetA)
并在 update
中做同样的事情
let update score event =
match event with
| IncA -> {score with ScoreA = score.ScoreA + 1}
| DecA -> {score with ScoreA = max (score.ScoreA - 1) 0}
| IncB -> {score with ScoreB = score.ScoreB + 1}
| DecB -> {score with ScoreB = max (score.ScoreB - 1) 0}
| New -> zero
| SetA -> System.Windows.MessageBox.Show("TextChanged","RoutedEv") |> ignore ; score
回到不是您所期望的 部分,我假设您希望记分牌中的分数在您更改 TextBox.Text
值时更新。
正如您所注意到的,没有(纯粹的)方法可以使用当前的 controller
将 TextBox.Text
值带入 update
中.
由于 SetX 行为未修复,这与 IncX、DecX 或 New 事件不同。
选项:
您可以将 Controller 的签名更改为
Score -> ScoringEvent -> string option -> Score
并使用选项值来处理update中的 SetX 事件
有趣。您可以处理
ViewModel
中的所有内容。 记录的不可变特性强制使用OneWay Binding
。我会保持它不可变,但您可以(分解)组合 ViewModel 中的所有内容。
尝试
View 模型
type MainViewModel(controller : Score -> ScoringEvent -> Score) as self =
inherit EventViewModelBase<ScoringEvent>()
let scoreA = self.Factory.Backing(<@ self.ScoreA @>, 0)
let scoreB = self.Factory.Backing(<@ self.ScoreB @>, 0)
let updateVM score =
scoreA.Value <- score.ScoreA
scoreB.Value <- score.ScoreB
let eventHandler ev =
updateVM <| controller {ScoreA = scoreA.Value ; ScoreB = scoreB.Value} ev
do
self.EventStream
|> Observable.add eventHandler
member this.IncA = this.Factory.EventValueCommand(IncA)
member this.DecA = this.Factory.EventValueCommandChecked(DecA, (fun _ -> this.ScoreA > 0), [ <@@ this.ScoreA @@> ])
member this.IncB = this.Factory.EventValueCommand(IncB)
member this.DecB = this.Factory.EventValueCommandChecked(DecB, (fun _ -> this.ScoreB > 0), [ <@@ this.ScoreB @@> ])
member this.NewGame = this.Factory.EventValueCommand(New)
member __.ScoreA
with get() = scoreA.Value
and set v = scoreA.Value <- v
member __.ScoreB
with get() = scoreB.Value
and set v = scoreB.Value <- v
XAML
<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Bottom" Height="75" Orientation="Horizontal" Background="#FF3A3A3A">
<Button Height="70" Width="70" Margin="2" Command="{Binding NewGame}">
<TextBlock Text="New" FontSize="18"></TextBlock>
</Button>
<TextBox Text="{Binding ScoreA, UpdateSourceTrigger=PropertyChanged}"
Margin="2" FontSize="18" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
</TextBox>
</StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Background="#FF024D70" Grid.Column="0">
<Grid>
<Viewbox>
<Label Content="{Binding ScoreA}" ContentStringFormat="D2" FontFamily="Lucida Console"></Label>
</Viewbox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Command="{Binding DecA}" Height="70" Width="70" VerticalAlignment="Bottom" Opacity="0.5" Margin="20">
<TextBlock Text="-" FontSize="36" Height="60"></TextBlock>
</Button>
<Button Command="{Binding IncA}" Height="70" Width="70" VerticalAlignment="Bottom" Opacity="0.5" Margin="20">
<TextBlock Text="+" FontSize="36" Height="60"></TextBlock>
</Button>
</StackPanel>
</Grid>
</Border>
<Border Background="#FF7E0E03" Grid.Column="1">
<Grid>
<Viewbox>
<Label Content="{Binding ScoreB}" ContentStringFormat="D2" FontFamily="Lucida Console"></Label>
</Viewbox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Command="{Binding DecB}" Height="70" Width="70" VerticalAlignment="Bottom" Opacity="0.5" Margin="20">
<TextBlock Text="-" FontSize="36" Height="60"></TextBlock>
</Button>
<Button Command="{Binding IncB}" Height="70" Width="70" VerticalAlignment="Bottom" Opacity="0.5" Margin="20">
<TextBlock Text="+" FontSize="36" Height="60"></TextBlock>
</Button>
</StackPanel>
</Grid>
</Border>
</Grid>
</DockPanel>
注释
Score.ScoreX
更改为ScoreX
Text="{Binding Score.ScoreA, Mode=OneWay}"
更改为Text="{Binding ScoreA, UpdateSourceTrigger=PropertyChanged}"
- 删除了
Interaction.Trigger
关于wpf - 在 F# WPF MVVM 应用程序中绑定(bind)到 TextBox 的 TextChanged 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41539544/