为什么我的ValueConverter没有被触发?
当我的视图模型的构造函数被执行时,我的值转换器被触发。但是,当我为Cells属性分配新值时,它不会被触发。
我希望这一行能够触发我的价值转换器更新:
this.Cells <- grid |> cycleThroughCells
|> Map.toSeq
|> Seq.map snd
|> Seq.toList
但它没有。
我有以下ViewModel:
type ViewModel() as this =
inherit ViewModelBase()
let rowCount = 6
let mutable grid = rowCount |> createGrid
|> setCell { X=3; Y=1; State=Alive }
|> setCell { X=3; Y=0; State=Alive }
|> setCell { X=4; Y=1; State=Alive }
let mutable _cells = grid |> Map.toSeq
|> Seq.map snd
|> Seq.toList
let cycleHandler _ =
this.Cells <- grid |> cycleThroughCells
|> Map.toSeq
|> Seq.map snd
|> Seq.toList
member this.Play =
DelegateCommand ((fun _ -> let timer = createTimer 500 cycleHandler
do while true do
do Async.RunSynchronously timer), fun _ -> true) :> ICommand
member this.Cells
with get() = _cells
and set(value) =
_cells <- value
base.NotifyPropertyChanged(<@ this.Cells @>)
我的ViewModelBase如下:
open System.ComponentModel
open Microsoft.FSharp.Quotations.Patterns
type ViewModelBase () =
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
let getPropertyName = function
| PropertyGet(_,pi,_) -> pi.Name
| _ -> invalidOp "Expecting property getter expression"
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
member private this.NotifyPropertyChanged propertyName =
propertyChanged.Trigger(this,PropertyChangedEventArgs(propertyName))
member this.NotifyPropertyChanged quotation =
quotation |> getPropertyName |> this.NotifyPropertyChanged
我的XAML如下:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Client;assembly=Client"
Background="Black"
Title="Game of Life" Height="450" Width="500">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Window.Resources>
<local:StateToBrushConverter x:Key="StateToBrushConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Grid.Row="0" Grid.Column="0" Fill="{Binding Cells[0], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="0" Grid.Column="1" Fill="{Binding Cells[1], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="0" Grid.Column="2" Fill="{Binding Cells[2], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="0" Grid.Column="3" Fill="{Binding Cells[3], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="0" Grid.Column="4" Fill="{Binding Cells[4], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="0" Grid.Column="5" Fill="{Binding Cells[5], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="1" Grid.Column="0" Fill="{Binding Cells[6], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="1" Grid.Column="1" Fill="{Binding Cells[7], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="1" Grid.Column="2" Fill="{Binding Cells[8], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="1" Grid.Column="3" Fill="{Binding Cells[9], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="1" Grid.Column="4" Fill="{Binding Cells[10], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="1" Grid.Column="5" Fill="{Binding Cells[11], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="2" Grid.Column="0" Fill="{Binding Cells[12], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="2" Grid.Column="1" Fill="{Binding Cells[13], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="2" Grid.Column="2" Fill="{Binding Cells[14], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="2" Grid.Column="3" Fill="{Binding Cells[15], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="2" Grid.Column="4" Fill="{Binding Cells[16], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="2" Grid.Column="5" Fill="{Binding Cells[17], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="3" Grid.Column="0" Fill="{Binding Cells[18], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="3" Grid.Column="1" Fill="{Binding Cells[19], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="3" Grid.Column="2" Fill="{Binding Cells[20], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="3" Grid.Column="3" Fill="{Binding Cells[21], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="3" Grid.Column="4" Fill="{Binding Cells[22], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="3" Grid.Column="5" Fill="{Binding Cells[23], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="4" Grid.Column="0" Fill="{Binding Cells[24], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="4" Grid.Column="1" Fill="{Binding Cells[25], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="4" Grid.Column="2" Fill="{Binding Cells[26], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="4" Grid.Column="3" Fill="{Binding Cells[27], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="4" Grid.Column="4" Fill="{Binding Cells[28], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="4" Grid.Column="5" Fill="{Binding Cells[29], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="5" Grid.Column="0" Fill="{Binding Cells[30], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="5" Grid.Column="1" Fill="{Binding Cells[31], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="5" Grid.Column="2" Fill="{Binding Cells[32], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="5" Grid.Column="3" Fill="{Binding Cells[33], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="5" Grid.Column="4" Fill="{Binding Cells[34], Converter={StaticResource StateToBrushConverter}}" />
<Rectangle Grid.Row="5" Grid.Column="5" Fill="{Binding Cells[35], Converter={StaticResource StateToBrushConverter}}" />
<Button Grid.Row="6" Grid.Column="1" Content="Go!" Command="{Binding Play}" />
</Grid>
</Window>
我的ValueConverter如下:
type StateToBrushConverter() =
interface IValueConverter with
member x.Convert(value, targetType, parameter, culture) =
let cell = value :?> Cell
match cell.State with
| Alive -> SolidColorBrush(Colors.LightGreen) :> obj
| Dead -> SolidColorBrush(Colors.Black) :> obj
member x.ConvertBack(value, targetType, parameter, culture) = failwith "Not implemented yet"
答案 0 :(得分:4)
当我尝试运行此代码时,我得到了异常。 不确定,这可能是应该的,但是这段代码对我没有错误:
type MainViewModel() as self =
inherit ViewModelBase()
let rowCount = 6
let mutable grid = rowCount |> createGrid
|> setCell { Y=2; X=1; State=Alive }
|> setCell { Y=2; X=2; State=Alive }
|> setCell { Y=3; X=2; State=Alive }
|> setCell { Y=3; X=3; State=Alive }
let mutable _cells = grid |> Map.toSeq
|> Seq.map snd
|> Seq.toList
let mutable count = 0
let mutable isEnabled = true
let cycleHandler _ =
_cells <- grid |> cycleThroughCells
|> Map.toSeq
|> Seq.map snd
|> Seq.toList
count <- count + 1
self.NotifyPropertyChanged(<@ self.Cells @>)
self.NotifyPropertyChanged(<@ self.Count @>)
let change _ =
isEnabled <- false
self.NotifyPropertyChanged(<@ self.IsEnabled @>)
async
{
while true do
do! Async.Sleep 2000
cycleHandler()
}
|> Async.Start
member __.Play = DelegateCommand (change, fun _ -> isEnabled) :> ICommand
member __.N = rowCount
member __.Cells = _cells
member __.Count = count
member __.IsEnabled = isEnabled
我改变了你的Xaml,因为我不认为描述36个矩形是个好主意。 一种选择是使用ListBox:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Go!" Command="{Binding Play}" IsEnabled="{Binding IsEnabled}" Margin="5" HorizontalAlignment="Right" />
<TextBlock Grid.Row="0" Text="{Binding Count}" Margin="5" HorizontalAlignment="Left"></TextBlock>
<ListBox Grid.Row="1" Margin="2" ItemsSource="{Binding Cells}" IsEnabled="False"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding N}" Columns="{Binding N}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Rectangle Stretch="Fill"
Fill="{Binding Converter={StaticResource StateToBrushConverter}}"></Rectangle>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
因此,您可以根据rowCount的值创建不同维度的网格。
我添加了一个变量“count”,表示即使图片没有改变,也会以指定的间隔调用该函数。
结果:
答案 1 :(得分:2)
我认为问题在于你绑定到列表中的各个元素,但是为列表本身触发NotifyPropertyChanged。您是否尝试使用ObservableCollection替换列表并使用Clear
+ AddRange
在每个tick上重新填充它?