Пользовательский интерфейс Windows (UWP или 8.1) в F# интерактивный
Ссылаясь на библиотеки WPF по умолчанию, довольно легко сделать все, что вы могли бы сделать, используя 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)
... а затем нажмите кнопку, чтобы увидеть, как это работает. Это кажется довольно мощным способом создания компонентов пользовательского интерфейса.
Есть ли способ сделать то же самое с пространством имен Windows.UI /controls/UI Framework - загрузить некоторые сборки в 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)
2 ответа
Для сборок WinRT компилятор не поддерживается, поэтому вы не сможете ссылаться на сборку, поскольку пытаетесь это сделать, и правильно использовать типы в них.
С другой стороны... поскольку среда выполнения.NET имеет встроенную поддержку типов WinRT, вы можете использовать отражение для загрузки этих типов и доступа к их членам. Приложив много усилий, вы могли бы даже создать провайдера типов, чтобы обеспечить чистый фасад поверх этого отражения и создать впечатление, что вы можете использовать типы напрямую. Вот небольшой пример того, как напрямую вызвать WinRT API из F# через отражение:
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")
Насколько я понимаю, пока нет поддержки FW для UWP.
Посмотрите, например, этот свежий открытый номер.