Open10

Avalonia.FuncUIについて色々試す。

anagoanago

val example: Tree.Tree list =
[Leaf { Id = b228b76c-f498-447b-8573-e7395a3b3e4c
Name = "渡辺 翼" }; Node { Id = 345d03ef-fc37-400d-9cd4-d41366796f4e
Name = "佐藤 大和"
SubTree = <seq> };
Node { Id = 69a7e00a-0030-4a1f-b2e6-b02b859eec58
Name = "中村 杏"
SubTree = <seq> }]

anagoanago

こういう方法もあるのか

type Validatable<'t, 'error when ^t: (static member validate: 't -> Result<'t, 'error>)> = 't

let inline validate (x: Validatable<'t, 'error>) =
    (^t: (static member validate: 't -> Result<'t, 'error>) x)

open System
type String10 =
    | String10 of string
    static member validate(String10 str) =
            if String.IsNullOrEmpty(str) then
                Error [ "NullOrEmpty" ]
            elif String.length str > 10 then
                Error [ "Over 10" ]
            else
                (String10 >> Ok) str
            
String10 "test" |> validate
// val it: Result<String10,string list> = Ok (String10 "test")

String10 "test         fdafdafdfd t" |> validate
// val it: Result<String10,string list> = Error ["Over 10"]
anagoanago

FuncControlTemplateってどうすれば良いんだろうね

module ThinkingTemplate =
    open System.Runtime.CompilerServices
    open Avalonia
    open Avalonia.Controls
    open Avalonia.Controls.Shapes
    open Avalonia.Controls.Primitives
    open Avalonia.Controls.Templates
    open Avalonia.Media
    open Avalonia.Layout
    open Avalonia.FuncUI
    open Avalonia.FuncUI.Types
    open Avalonia.FuncUI.DSL

    type TemplatedControl with

        static member template(viewFunc: 'templatedControl -> INameScope -> #IControl) :IAttr<'templatedControl> =
            FuncControlTemplate<'templatedControl>(fun x scope -> viewFunc x scope :> IControl)
            |> TemplatedControl.template

    module AvaloniaObject =
        let bind prop observable (x: 'b :> AvaloniaObject) : 'b =
            let binding = AvaloniaObjectExtensions.ToBinding observable
            x[AvaloniaProperty.op_OnesComplement prop] <- binding
            x

    type IComponentContext with
        member this.useAvaloniaPropertyWith
            (
                property: AvaloniaProperty<'x>,
                [<CallerLineNumber>] ?callerLineNumber: int
            ) =
            let identity = Option.get callerLineNumber

            fun (mapper: 'x -> 'y) (target: 'a :> AvaloniaObject) ->
                let state = this.useState (target.GetValue property |> mapper, true, identity)

                this.useEffect (
                    (fun () ->
                        target.GetObservable property
                        |> Observable.map mapper
                        |> Observable.subscribe state.Set),
                    [ EffectTrigger.AfterInit ],
                    identity
                )

                state

        member this.useAvaloniaProperty(property: AvaloniaProperty<'x>, [<CallerLineNumber>] ?callerLineNumber: int) =
            let identity = Option.get callerLineNumber

            fun (target: 'a :> AvaloniaObject) ->
                let state = this.useState (target.GetValue property, true, identity)

                this.useEffect (
                    (fun () ->
                        target.GetObservable property
                        |> Observable.subscribe state.Set),
                    [ EffectTrigger.AfterInit ],
                    identity
                )

                state

    let useBindindg () =
        ToggleButton.create [
            ToggleButton.template (fun templatedToggleButton scope ->
                Border(
                    Background = Brushes.Transparent,
                    Width = 12,
                    Height = 14,
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    Child =
                        (Path(
                            HorizontalAlignment = HorizontalAlignment.Center,
                            VerticalAlignment = VerticalAlignment.Center,
                            Data = Geometry.Parse "M 0 2 L 4 6 L 0 10 Z"
                         )
                         |> AvaloniaObject.bind
                             Path.FillProperty
                             (templatedToggleButton.GetObservable ContentControl.ForegroundProperty))
                )
                |> AvaloniaObject.bind
                    Border.RenderTransformProperty
                    (templatedToggleButton.GetObservable ToggleButton.IsCheckedProperty
                     |> Observable.map (fun isChecked ->
                         if isChecked.HasValue && isChecked.Value then
                             RotateTransform 0.0
                         else
                             RotateTransform 45.0)))
        ]

    let useComponent () =
        ToggleButton.create [
            ToggleButton.template (fun templatedToggleButton scope ->
                Component (fun ctx ->
                    let fill =
                        templatedToggleButton
                        |> ctx.useAvaloniaProperty ToggleButton.ForegroundProperty

                    let isChecked =
                        templatedToggleButton
                        |> ctx.useAvaloniaPropertyWith ToggleButton.IsCheckedProperty (fun o -> o.HasValue && o.Value)

                    ctx.attrs [
                        Component.background Brushes.Transparent
                        Component.width 12
                        Component.height 14
                        Component.verticalAlignment VerticalAlignment.Center
                        Component.horizontalAlignment HorizontalAlignment.Center
                        if isChecked.Current then
                            RotateTransform 45.0 |> Component.renderTransform
                    ]

                    Path.create [
                        Path.fill fill.Current
                        Path.horizontalAlignment HorizontalAlignment.Center
                        Path.verticalAlignment VerticalAlignment.Center
                        Path.data "M 0 2 L 4 6 L 0 10 Z"
                    ]))
        ]