【问题标题】:Windows UI (UWP or 8.1) in F# interactiveF# 交互中的 Windows UI(UWP 或 8.1)
【发布时间】:2016-07-13 05:50:14
【问题描述】:

通过引用默认的 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()

...您可以在窗口仍然打开时对其进行操作...

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

...然后单击按钮以查看它的工作原理。这似乎是构建 UI 组件的一种非常强大的方式。

有没有办法用 Windows.UI 命名空间/控件/UI 框架做同样的事情——在 F# 交互中加载一些程序集并即时实例化 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"

...这样做可以让我智能感知到 Windows.UI 命名空间。但是当我尝试实例化某些东西时:

Windows.UI.Xaml.Application()

我明白了:

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)

【问题讨论】:

    标签: f# uwp uwp-xaml f#-interactive


    【解决方案1】:

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

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

    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")
    

    【讨论】:

    • “不支持 WinRT 程序集的编译器”是什么意思? F# 编译器无法从.winmd 文件加载程序集? winmd 是否意味着它是一个 WinRT 程序集?
    • 是的,我的意思是编译器不知道包含“Windows 运行时”组件的 .winmd 程序集,尽管它们很接近(它们只包含元数据,例如,但没有实现)。
    【解决方案2】:

    我的理解是目前还没有对 UWP 的 F# 支持。
    比如看看这个新鲜的open issue

    【讨论】:

    • 问题现已关闭。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    相关资源
    最近更新 更多