Open10
Avalonia.FuncUIについて色々試す。
作業用リポジトリ
このコード例のFuncUI版を作成したい
データ定義できた
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> }]
こういう方法もあるのか
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"]
HugeTree追加。
最後の関数だけなら割とシンプル?
良い感じ?
追加―
良い感じになったのでライブラリ化することにした
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"
]))
]