F#interactive中的Windows UI(UWP或8.1)

Ove*_*urg 5 f# f#-interactive uwp uwp-xaml

通过引用默认的WPF DLL,使用仅代码的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()
Run Code Online (Sandbox Code Playgroud)

......当窗口仍然打开时你可以操纵它......

button.Click.Add (fun _ ->
    button.Content <-
        button.Content :?> string |> fun x -> (x + "!") :> obj)
Run Code Online (Sandbox Code Playgroud)

...然后单击按钮以查看其工作情况.这似乎是构建UI组件的一种非常强大的方法.

有没有办法用Windows.UI命名空间/控件/ UI框架做同样的事情 - 在F#interactive中加载一些程序集并动态实例化UI组件?

我天真地尝试引用似乎相关的文件:

#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"
Run Code Online (Sandbox Code Playgroud)

...这样做可以让我智能地进入Windows.UI命名空间.但是当我尝试实例化时:

Windows.UI.Xaml.Application()
Run Code Online (Sandbox Code Playgroud)

我明白了:

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)

kvb*_*kvb 3

WinRT 程序集没有编译器支持,因此当您尝试干净地执行和使用其中的类型时,将无法引用程序集。

\n\n

另一方面...由于 .NET 运行时对 WinRT 类型具有本机支持,因此您可以使用反射来加载这些类型并访问其成员。经过大量的努力,您甚至可以构建一个类型提供程序来为该反射提供干净的 fa\xc3\xa7ade 并使其看起来好像您可以直接使用这些类型。以下是如何通过反射从 F# 直接调用 WinRT API 的小示例:

\n\n
open System.Reflection\n\nlet (?) (o:obj) s : \'a =\n    let rec build ty args =\n        if Reflection.FSharpType.IsFunction ty then\n            let dom, rng = Reflection.FSharpType.GetFunctionElements ty\n            let mkArgs =\n                if dom = typeof<unit> then\n                    if Reflection.FSharpType.IsFunction rng then failwith "Unit as non-final argument in curried definition?"\n                    fun _ -> args\n                else\n                    fun arg -> arg::args\n            Reflection.FSharpValue.MakeFunction(ty, fun o -> build rng (mkArgs o))\n        else\n            let rcvr,ty,flags =\n                match o with\n                | :? System.Type as ty -> null,ty,BindingFlags.Static\n                | _ -> o,o.GetType(),BindingFlags.Instance\n            let flags = flags ||| BindingFlags.Public\n            let meth =\n                if Reflection.FSharpType.IsFunction typeof<\'a> then\n                    query {\n                        for m in ty.GetMethods(flags) do\n                        where (m.Name = s)\n                        where (m.GetParameters().Length = args.Length)\n                        exactlyOne\n                    }                    \n                else\n                    ty.GetProperty(s, flags).GetGetMethod()\n            meth.Invoke(rcvr, args |> List.toArray)\n\n    build typeof<\'a> [] :?> \'a\n\nlet Clipboard = System.Type.GetType(@"Windows.ApplicationModel.DataTransfer.Clipboard, Windows.ApplicationModel, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime")\n\nClipboard?GetContent()?AvailableFormats |> Seq.iter (printfn "%s")\n
Run Code Online (Sandbox Code Playgroud)\n

  • 是的,我的意思是编译器不知道包含“Windows 运行时”组件的 .winmd 程序集,并且它们不完全是标准的 .NET 程序集,尽管它们很接近(例如,它们仅包含元数据,但不包含实现) )。 (2认同)