F#でWPF --- スライダーCommand
今回はdouble値をCommandで送るSliderを作成します。
SliderにはCommandプロパティが用意されていないため、Behaviorを作成します。
Behaviorの基本は下記記事を参照してください。
F#でWPF --- チェックボックスCommand --- Behavior利用 - 何でもプログラミング
ValueChangedイベント
SliderにはValueChangedイベントがありますが、ViewModelからのValueの変更でも発行されてしまいます。
ループ構造は予期せぬ挙動を招く可能性がありますので、今回はViewModel側からのValueの変更とユーザーからのValueの変更を分離するよう実装します。
SliderBehavior
ViewModelからのValueの変更の場合、一時変数に入力をセットしておきます。
ValueChangedイベントが発行されたときに一時変数の値と同じならViewModelからの変更、異なる場合はユーザーからの変更と考えられます。
ViewModelからのValueの値がMinimum~Maximunに収まっていない場合、収まった値がSlider.Valueに設定されてしまう(ValueChangedが発行されてしまう)ので、事前にMinimum~Maximumに収めています。
BehaviorBaseは下記記事を参照してください。
F#でWPF --- チェックボックスCommand --- Behavior利用 - 何でもプログラミング
DependencyProperty.changedは下記記事を参照してください。
F#でWPF --- テキストボックスCommand --- 1文字変更毎に発行 - 何でもプログラミング
type SliderBehavior() = inherit BehaviorBase<Slider>() static member val CommandProperty = DependencyProperty.Register("Command", typeof<ICommand>, typeof<SliderBehavior>) member this.Command with get() = this.GetValue(SliderBehavior.CommandProperty) :?> ICommand and set(x:ICommand) = this.SetValue(SliderBehavior.CommandProperty, x) static member val ValueProperty = DependencyProperty.Register("Value", typeof<double>, typeof<SliderBehavior>) member this.Value with get() = this.GetValue(SliderBehavior.ValueProperty) :?> double and set(x:double) = this.SetValue(SliderBehavior.ValueProperty, x) override this.OnAttached control = let mutable value = control.Value [ control.ValueChanged.Subscribe (fun x -> if value <> x.NewValue then value <- x.NewValue if this.Command <> null then this.Command.Execute(value)) DependencyProperty.changed<double> SliderBehavior.ValueProperty this |> Observable.subscribe (fun x -> let clamp min max = function | x when x < min -> min | x when max < x -> max | x -> x value <- x |> clamp control.Minimum control.Maximum control.Value <- value) ]
作成するアプリケーション
スライダーとスライダーの値を表示するテキストボックスからなります。
アプリケーションコード
SliderのIsSnapToTickEnabledをtrueにすると、TickFrequencyの値でスライダーを刻むことができるようになります。(TickFrequencyのデフォルトは1です。)
F#で利用しているDataContextは下記記事を参照してください。
F#でWPF --- Elm Architectureを利用したMVVM - 何でもプログラミング
またF#でWPFプロジェクトを作成する方法は下記記事を参照してください。
F#でWPF --- ウィンドウ表示 - 何でもプログラミング
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:local="clr-namespace:Behaviors;assembly=Behaviors" Title="MainWindow" Height="80" Width="220"> <Grid> <Slider IsSnapToTickEnabled="True" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="150"> <i:Interaction.Behaviors> <local:SliderBehavior Command="{Binding SetValue}" Value="{Binding Value}" /> </i:Interaction.Behaviors> </Slider> <TextBlock Text="{Binding Value}" HorizontalAlignment="Left" Margin="165,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/> </Grid> </Window>
F#
open System open System.Windows type Model = { Value : double } type Msg = SetValue of double let updateModel model msg = match msg with | SetValue x -> { model with Value = x } [<STAThread>] [<EntryPoint>] let main argv = let window = Application.LoadComponent(Uri("MainWindow.xaml", UriKind.Relative)) :?> Window window.DataContext <- DataContext({ Value = 0.0 }, updateModel, id) Application().Run(window) |> ignore 0