Search code examples
f#protectedavalonia

Avalonia FuncUI PointerPressedEventArgs, how to access protected member without using reflection?


In my F# Avalonia FuncUI desktop app, I wanted a callback when the user presses the mouse 'Back' button in my FuncUI component. I eventually got it working using reflection, as below. I was wondering if I am missing a cleaner or more obvious way of doing this? Should I be raising this as an issue on the FuncUI github repository?

open Avalonia.FuncUI

let getProtectedPropertyValue (name: string) (obj: obj) =
  let propertyInfo = 
    obj.GetType().GetProperty(
      name, BindingFlags.Instance |||
      BindingFlags.NonPublic ||| BindingFlags.Public)

  if propertyInfo <> null && propertyInfo.CanRead then
    propertyInfo.GetValue(obj)
  else
    failwith $"Property '{name}' not gettable"

ctx.attrs [
  
  Component.onPointerPressed (fun event -> 
    
    let properties = 
      getProtectedPropertyValue "Properties" event :?>
        PointerPointProperties
    
    if properties.IsXButton1Pressed then
      DoSomething()
  )
]

Solution

  • Thanks to JL0PD's comment, I discovered an Avalonia GitHub Issue, which has the answer to how to directly access the property I was after, without resorting to reflection. Here is the corrected code in F# for Avalonia FuncUI:

    open Avalonia.FuncUI
    
    Component(fun ctx ->
      ctx.attrs [
      
        Component.onPointerPressed (fun event ->           
    
          let properties = event.GetCurrentPoint(ctx.control).Properties
        
          if properties.IsXButton1Pressed then    
            event.Handled <- true // prevent second callback on pointer button release
            DoSomething()
        )
      ]
    

    I was later caught out by the event happening twice, which I suspect is because it is called for both press and release of the button.