📷

Avalonia.FuncUI.Elmishでフォーカス制御

に公開

Avalonia.FuncUIでTextBoxなどのフォーカスを制御する方法についての記事です。

公式のCommon QuestionsにComponentsでのサンプルコードはあるのですが、Elmishで同じことをするにはどうすればいいのかがわからず、ググっても出ず、ChatGPTに尋ねれば存在しない関数を回答するなど、かなり右往左往してしまいました。

View.withOutlet関数でそのコントロールの参照が取れるので、それを使えばよいだけでした...

open Avalonia.FuncUI.DSL
open Avalonia.Controls
open Avalonia.Layout
open Avalonia.Media

type State = {
    textBoxAFocus: bool
    textBoxBFocus: bool
}

let init () = {
    textBoxAFocus = false
    textBoxBFocus = false
}

type Msg =
    | TextBoxAFocusChanged of bool
    | TextBoxBFocusChanged of bool

let mutable textBoxA = None
let mutable textBoxB = None

let update msg state =
    match msg with
    | TextBoxAFocusChanged focus -> { state with textBoxAFocus = focus }
    | TextBoxBFocusChanged focus -> { state with textBoxBFocus = focus }

let view (state: State) dispatch =
    StackPanel.create [
        StackPanel.margin 10
        StackPanel.spacing 10
        StackPanel.children [
            TextBox.create [
                TextBox.onGotFocus (fun _ -> TextBoxAFocusChanged true |> dispatch)
                TextBox.onLostFocus (fun _ -> TextBoxAFocusChanged false |> dispatch)
            ]
            |> View.withOutlet (fun tb -> textBoxA <- Some tb)
            TextBox.create [
                TextBox.onGotFocus (fun _ -> TextBoxBFocusChanged true |> dispatch)
                TextBox.onLostFocus (fun _ -> TextBoxBFocusChanged false |> dispatch)
            ]
            |> View.withOutlet (fun tb -> textBoxB <- Some tb)
            StackPanel.create [
                StackPanel.orientation Orientation.Horizontal
                StackPanel.margin 10
                StackPanel.spacing 10
                StackPanel.children [
                    Button.create [
                        Button.content "Focus A"
                        Button.background (
                            if state.textBoxAFocus then Brushes.Green else Brushes.Red
                        )
                        Button.onClick (fun _ ->
                            textBoxA
                            |> Option.iter (fun tb -> tb.Focus() |> ignore))
                    ]
                    Button.create [
                        Button.content "Focus B"
                        Button.background (
                            if state.textBoxBFocus then Brushes.Green else Brushes.Red
                        )
                        Button.onClick (fun _ ->
                            textBoxB
                            |> Option.iter (fun tb -> tb.Focus() |> ignore))
                    ]
                ]
            ]
        ]
    ]

Discussion