By referencing the default WPF DLLs, it's pretty easy to do anything you could do using code-only WPF:
#r "PresentationCore.dll"
#r "PresentationFramework.dll"
// ...other DLLs...
#r "WindowsBase.dll"
let window = System.Windows.Window()
let panel = System.Windows.Controls.StackPanel()
let button = System.Windows.Controls.Button()
panel.Children.Add button
button.Content <- "hi"
window.Content <- panel
window.Show()
... and you can manipulate it while the window is still open...
button.Click.Add (fun _ ->
button.Content <-
button.Content :?> string |> fun x -> (x + "!") :> obj)
...and then click the button to see it work. It seems like a pretty powerful way to build up UI components.
Is there any way to do the same thing with the Windows.UI namespace/controls/UI framework -- load some assemblies in F# interactive and instantiate UI components on the fly?
I've naively tried referencing the files that seemed relevant:
#r @"C:\Program Files (x86)\Windows Kits\10\References\Windows.Foundation.UniversalApiContract\2.0.0.0\Windows.Foundation.UniversalApiContract.winmd"
#r @"C:\Program Files (x86)\Windows Kits\10\References\Windows.Foundation.FoundationContract\2.0.0.0\Windows.Foundation.FoundationContract.winmd"
...and doing that gets me intellisense into the Windows.UI namespaces. But when I try to instantiate something:
Windows.UI.Xaml.Application()
I get:
error FS0193: Could not load file or assembly 'file:///C:\Program Files (x86)\Windows Kits\10\References\Windows.Foundation.UniversalApiContract\2.0.0.0\Windows.Foundation.UniversalApiContract.winmd' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
There is no compiler support for WinRT assemblies, so you're not going to be able to reference an assembly as you're attempting to do and use the types in them cleanly.
On the other hand... since the .NET runtime has native support for WinRT types, you can use reflection to load those types and access their members. With a lot of effort, you could even build a type provider to provide a clean façade over that reflection and make it appear as though you can use the types directly. Here's a small example of how to directly call a WinRT API from F# via reflection:
open System.Reflection
let (?) (o:obj) s : 'a =
let rec build ty args =
if Reflection.FSharpType.IsFunction ty then
let dom, rng = Reflection.FSharpType.GetFunctionElements ty
let mkArgs =
if dom = typeof<unit> then
if Reflection.FSharpType.IsFunction rng then failwith "Unit as non-final argument in curried definition?"
fun _ -> args
else
fun arg -> arg::args
Reflection.FSharpValue.MakeFunction(ty, fun o -> build rng (mkArgs o))
else
let rcvr,ty,flags =
match o with
| :? System.Type as ty -> null,ty,BindingFlags.Static
| _ -> o,o.GetType(),BindingFlags.Instance
let flags = flags ||| BindingFlags.Public
let meth =
if Reflection.FSharpType.IsFunction typeof<'a> then
query {
for m in ty.GetMethods(flags) do
where (m.Name = s)
where (m.GetParameters().Length = args.Length)
exactlyOne
}
else
ty.GetProperty(s, flags).GetGetMethod()
meth.Invoke(rcvr, args |> List.toArray)
build typeof<'a> [] :?> 'a
let Clipboard = System.Type.GetType(@"Windows.ApplicationModel.DataTransfer.Clipboard, Windows.ApplicationModel, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime")
Clipboard?GetContent()?AvailableFormats |> Seq.iter (printfn "%s")
My understanding is that there is no F# support for UWP yet.
See for instance this fresh open issue.