Avalonia.FuncUI
Avalonia.FuncUI copied to clipboard
Underlying Control Access
So I'm doing some things involving drag and drop, and am very interested in functions like GetInputElementsAt(). Note that using the obvious functions like OnPointerEnter() will not work since in a drag and drop operation, the first control has focus as long as the mouse button is down, and other potential target controls will not get mouse events during this time. The problem is that this function returns a list of Avalonia controls, and I need some way of going backwards to figure out how to properly wire this information into an update event.
What's the best way of going about this sort of thing? Would I create a custom user control and wire up an event? Is there a way to do things like AddHandler() for DragDrop events and have this visible to the DSL? What happens when things are regenerated in create()?
Finally, how does using inherited classes in the DSL work? For instance, maybe I have a Button and I need to put handlers on inherited InputElement events. I don't see any of this in the examples.
I've never really used Drag&Drop in my applications, so had to google for it. Found this StackOverflow questions to see how this should work
Few extension methods
[<AutoOpen>]
module Extensions =
type Interactive with
static member allowDrop<'t when 't :> Interactive>(isAllowed) : IAttr<'t> =
AttrBuilder<'t>.CreateProperty<bool>(DragDrop.AllowDropProperty, isAllowed, ValueNone)
static member onDrop<'t when 't :> Interactive>(func: DragEventArgs -> unit, ?subPatchOptions) =
AttrBuilder<'t>.CreateSubscription<DragEventArgs>(DragDrop.DropEvent, func, ?subPatchOptions = subPatchOptions)
Create view
let view state dispatch =
StackPanel.create [
StackPanel.children [
TextBlock.create [
TextBlock.text "drag me"
TextBlock.background "purple"
TextBlock.height 80.
TextBlock.onPointerPressed
(fun e ->
let data = DataObject()
data.Set(DataFormats.Text, System.DateTime.Now.ToLongTimeString())
DragDrop.DoDragDrop(e, data, DragDropEffects.Copy) |> ignore)
]
TextBlock.create [
TextBlock.allowDrop true
TextBlock.text "drop here"
TextBlock.background "darkcyan"
TextBlock.height 80.
TextBlock.onDrop
(fun e -> printfn "drop %A" <| e.Data.Get(DataFormats.Text))
]
]
]
And current time get displayed in console.
There is one problem: Drop event raised twice when dragging control (bug), but raised once when dragging file from explorer (normal behavior)
There is a feature planned that would allow you to simple do something with the control reference on render. Don't know when I will have time for it as I currently don't use FuncUI in any work/side project. I'm happy to take PR's tho.
TextBlock.create [
TextBlock.useViewRef (fun textBlock -> ...)
]
There are now 2 ways of doing this:
- Using init functions
Button.create [
Button.init (fun button ->
button.Name <- "whatever"
)
]
- Using outlets
let mutable outlet: Button = null
let setOutlet value = outlet <- value
View.createWithOutlet setOutlet Button.create []