如何在F#中启用WinForms或WPF项目?

Mat*_*and 19 f# visual-studio

我安装了最新版本的Visual Studio 2017.我选择了F#语言支持和F#桌面支持.重新启动并转到文件 - >新项目后,我希望看到为F#启动新的WPF或WinForms项目的选项,但我没有任何此类选项.只有控制台,库,ASP.NET核心和教程.

如何为F#桌面应用程序启用或查找新项目模板?

Tom*_*cek 23

您可以在F#中创建WPF和WinForms应用程序.没有模板,但它肯定是可能的,许多人这样做.要创建一个简单的WinForms应用程序,您可以执行以下操作:

  • 创建一个新的控制台应用程 转到项目属性并将"应用程序"页面中的"输出类型"从"控制台应用程序"更改为"Windows应用程序"

  • 右键单击项目中的"References",并添加对"System.Windows.Forms"和"System.Drawing"的引用(在"Framework"选项卡中).

  • Program.fs以下内容替换代码:

    open System.Windows.Forms
    
    let f = new Form()
    f.Controls.Add(new Label(Text="Hello world!"))
    Application.Run(f)
    
    Run Code Online (Sandbox Code Playgroud)

对于任何更大的东西,你可能想要使用一个漂亮的F#GUI库,如Isaac或Gjallarhorn提到的FsXaml项目,但基本的第一步将是相同的 - 创建一个控制台项目,使其成为一个Windows项目,然后添加相关对GUI框架的引用.

  • "我假设如果我使用Windows窗体这条路线,我将需要创建表单布局并在没有视觉设计师帮助的情况下控制代码中的位置.这是正确的吗?"@Matthew MacFarland是的,你是对的,所以更好F#的选项是选择WPF. (2认同)
  • 如果选择带MVVM的WPF,还可以选择将视图(XAML)放在C#项目中,并在F#中使用视图模型和模型.虽然没有像FsXaml,MVC,Gjallarhorn和Elmish.WPF这样的更多F#'选项那么优雅,但我发现这样做不那么麻烦,而且对我来说也更快,因为可用的学习资源要多得多. (2认同)

Isa*_*ham 11

据我所知,在F#上没有WPF或WinForms的"开箱即用"模板,但(至少在VS2015中)有一组用于WPF应用的社区模板.说实话,你真的不需要模板,特别是如果你使用FSXaml项目,这使得它很容易手工完成(https://github.com/fsprojects/FsXaml).

  • @MatthewMacFarland是的,可以使用内置设计器编辑XAML文件. (3认同)

Pan*_*vos 10

这不是一个简单的答案.这些项目没有内置项目模板,因为Windows窗体和WPF设计器都不了解F#.我们刚刚获得了F#的ASP.NET核心模板,所以我们不应该抱怨......

另一方面,Winforms或WPF应用程序只是C#代码.您在设计器中执行的任何操作最终都是表单文件中的代码.Winforms或WPF应用程序是"仅"控制台应用程序,用于设置适当的环境并创建表单和控件.

使用XAML和WP 实际上更容易,尤其是在使用MVVM或类似架构的情况下.这是因为您可以与F#代码分开开发XAML标记并将数据绑定到XAML.您甚至可以创建一个WPF类库项目,在没有任何代码的情况下创建Windows,页面和控件,然后在F#项目中使用它们.

有一些库使这更容易.一种选择是Elmish.WPF.您可以在单独的项目中创建XAML页面和窗口,然后在F#中创建模型等,将它们绑定在一起并启动主窗体.如果检查repo的示例,大多数代码将记录和命令定义为F#函数,例如:

type ClockMsg =
    | Tick of DateTime

type ClockModel =
    { Time: DateTime }

type Msg =
    | ClockMsg of ClockMsg
    | Increment
    | Decrement
    | SetStepSize of int

type Model = 
    { Count: int
      StepSize: int
      Clock: ClockModel }
Run Code Online (Sandbox Code Playgroud)

let init() = { Count = 0; StepSize = 1; Clock = { Time = DateTime.Now }}

let clockUpdate (msg:ClockMsg) (model:ClockModel) =
    match msg with
    | Tick t -> { model with Time = t }

let update (msg:Msg) (model:Model) =
    match msg with
    | Increment -> { model with Count = model.Count + model.StepSize }
    | Decrement -> { model with Count = model.Count - model.StepSize }
    | SetStepSize n -> { model with StepSize = n }
    | ClockMsg m -> { model with Clock = clockUpdate m model.Clock }
Run Code Online (Sandbox Code Playgroud)

将它们绑定在一起相对简单:

let view _ _ = 
    let clockViewBinding : ViewBindings<ClockModel,ClockMsg> =
        [ "Time" |> Binding.oneWay (fun m -> m.Time) ]

    [ "Increment" |> Binding.cmd (fun m -> Increment)
      "Decrement" |> Binding.cmdIf (fun m -> Decrement) (fun m -> m.StepSize = 1)
      "Count" |> Binding.oneWay (fun m -> m.Count)
      "StepSize" |> Binding.twoWay (fun m -> (double m.StepSize)) (fun v m -> v |> int |> SetStepSize)
      "Clock" |> Binding.vm (fun m -> m.Clock) clockViewBinding ClockMsg ]
Run Code Online (Sandbox Code Playgroud)

并运行整个应用程序

[<EntryPoint;STAThread>]
 let main argv = 
     Program.mkSimple init update view
     |> Program.withSubscription subscribe
     |> Program.runWindow (Elmish.CounterViews.MainWindow())
Run Code Online (Sandbox Code Playgroud)

上面的代码来自Counter示例.XAML视图在CounterViews项目中定义.你甚至可以删除.cs文件,项目编译就好了.