专栏首页林德熙的博客dotnet 通过 Elmish.WPF 使用 F# 编写 WPF 应用

dotnet 通过 Elmish.WPF 使用 F# 编写 WPF 应用

本文来安利大家一个有趣而且强大的库,通过 F# 和 C# 混合编程编写 WPF 应用,可以在 WPF 中使用到 F# 强大的数据处理能力

在 GitHub 上完全开源 Elmish.WPF 库,请看 https://github.com/elmish/Elmish.WPF

在阅读本文之前,我期望大家已了解部分 F# 的知识。在学会 C# 基础知识之下,了解 F# 基础知识是很快的,而本文也仅仅只是用到很少的知识。大家都知道,使用 F# 能带来很好的数据处理能力,从 F# 语法层面带来的编写效率提升和编写逻辑的优化,而 F# 本身是没有带 GUI 可视化应用编程的。但是 F# 是在 dotnet 体系下的,天然就可以用上 dotnet 系的技术,当然就包括 WPF 了。因此上一句话说 F# 本身是没有带 GUI 可视化应用编程是完全错误的,因为 F# 可以非常方便调起 WPF 和 WinForms 等成熟的 UI 框架作为自身的可视化应用框架

通过 Elmish.WPF 库,将可以让开发更顺,以下是一个简单的例子。这个例子的代码完全放在 Elmish.WPF 库里,可以通过 https://github.com/elmish/Elmish.WPF 获取所有代码

咱依然通过 VS 创建一个空白的 C# 空白 WPF 程序,在此例子里面,几乎没有 C# 多少的戏份,只是为了使用 C# 更好的驱动 WPF 程序而已,因为部分初始化方法和类型等在 F# 写起来的代码量可不少。本文的主角将交给 XAML 和 F# 这两个语言

打开 App.xaml.cs 文件,咱将修改本文仅有的一点 C# 代码

  public partial class App : Application
  {
    public App()
    {
      this.Activated += StartElmish;
    }

    private void StartElmish(object sender, EventArgs e)
    {
      this.Activated -= StartElmish;
      Program.main(MainWindow);
    }
  }

以上代码的 Program 类是在 F# 项目里面编写的,也就是说 C# 语言只是胶水,用来做初始化的连接

接下来咱来创建一个简单的界面,这个界面如下

基本功能是点击加号和减号分别实现当前数值的加减

大概的 XAML 代码如下

  <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,25,0,0">
    <TextBlock Text="{Binding CounterValue, StringFormat='Counter value: {0}'}" Width="110" Margin="0,5,10,5" />
    <Button Command="{Binding Decrement}" Content="-" Margin="0,5,10,5" Width="30" />
    <Button Command="{Binding Increment}" Content="+" Margin="0,5,10,5" Width="30" />
    <TextBlock Text="{Binding StepSize, StringFormat='Step size: {0}'}" Width="70" Margin="0,5,10,5" />
    <Slider Value="{Binding StepSize}" TickFrequency="1" Maximum="10" Minimum="1" IsSnapToTickEnabled="True" Width="100" Margin="0,5,10,5" />
    <Button Command="{Binding Reset}" Content="Reset" Margin="0,5,10,5" Width="50" />
  </StackPanel>

在 XAML 中定义了命令和值的绑定,没有做实际的实现

接下来创建一个 F# 项目,将这个项目被刚才创建的 WPF 项目所引用,将 WPF 项目作为启动项目。运行的顺序是先启动 WPF 项目,进入 App 类里面,在 App 的 Activated 事件,调用 F# 项目的逻辑,然后接下来就交给 F# 来进行数据绑定,在 F# 项目中,将给 MainWindow 附加自身作为 DataContext 数据用于在 XAML 绑定

在 F# 的 Program.fs 文件里面添加如下代码

module Elmish.WPF.Samples.SingleCounter.Program

open Serilog
open Serilog.Extensions.Logging
open Elmish.WPF

type Model =
  { Count: int
    StepSize: int }

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

let init =
  { Count = 0
    StepSize = 1 }

let canReset = (<>) init

let update msg m =
  match msg with
  | Increment -> { m with Count = m.Count + m.StepSize }
  | Decrement -> { m with Count = m.Count - m.StepSize }
  | SetStepSize x -> { m with StepSize = x }
  | Reset -> init

let bindings () : Binding<Model, Msg> list = [
  "CounterValue" |> Binding.oneWay (fun m -> m.Count)
  "Increment" |> Binding.cmd Increment
  "Decrement" |> Binding.cmd Decrement
  "StepSize" |> Binding.twoWay(
    (fun m -> float m.StepSize),
    int >> SetStepSize)
  "Reset" |> Binding.cmdIf(Reset, canReset)
]

let designVm = ViewModel.designInstance init (bindings ())

let main window =

  let logger =
    LoggerConfiguration()
      .MinimumLevel.Override("Elmish.WPF.Update", Events.LogEventLevel.Verbose)
      .MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose)
      .MinimumLevel.Override("Elmish.WPF.Performance", Events.LogEventLevel.Verbose)
      .WriteTo.Console()
      .CreateLogger()

  WpfProgram.mkSimple (fun () -> init) update bindings
  |> WpfProgram.withLogger (new SerilogLoggerFactory(logger))
  |> WpfProgram.startElmishLoop window

十分简单的逻辑,在 F# 定义的命令等将可以通过 Elmish.WPF 库和 WPF 的 XAML 绑定,相当于 XAML 提供界面逻辑,而 F# 提供数据驱动的处理逻辑。各个语言的职责是 XAML 负责界面,而 F# 负责后台逻辑。将 XAML 和 F# 连接起来以及应用程序的启动是 C# 语言


本文会经常更新,请阅读原文: https://blog.lindexi.com/post/dotnet-%E9%80%9A%E8%BF%87-Elmish.WPF-%E4%BD%BF%E7%94%A8-F-%E7%BC%96%E5%86%99-WPF-%E5%BA%94%E7%94%A8.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,推荐使用RSS Stalker订阅博客,或者前往 CSDN 关注我的主页

无盈利,不卖课,做纯粹的技术博客

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • GitHub Action 新上线 WPF .NET Core 自动构建模板

    在很土豪的微软免费给大家提供 GitHub 的构建服务器受到了小伙伴们的一堆好评之后,微软最近推出了 WPF 的 .NET Core 版本的模板,可以快速上手 ...

    林德熙
  • dotnet 从入门到放弃的 500 篇文章合集

    博客包括 C#、WPF、UWP、dotnet core 、git 和 VisualStudio 和一些算法,所有博客使用 docx 保存

    林德熙
  • VisualStudio 通过外部调试方法快速调试库代码

    在开发的时候,我有一个很大的项目,里面包含了 1000 个项目,但是我需要调试里面的一个库,如果直接修改这个库,会让 VisualStudio 重新编译 90 ...

    林德熙
  • SourceYard 制作源代码包 控制台项目WPF 程序调试

    本文带大家走进SourceYard开发之旅 在项目开发中,将一个大的项目拆为多个小项目解耦,减少模块之间的耦合。因为如果将代码放在一起,即使有团队的约束,但只要...

    林德熙
  • 搭建一个自动化分析 DUMP 平台

    本文来告诉大家如何一步步搭建一个 DUMP 分析平台,核心是用来分析桌面端的应用软件,如 WPF 软件的 DUMP 文件。在开始之前需要说明的是,如果桌面端软件...

    林德熙
  • dotnet 配合 GitHub 的 Action 做自动推 Tag 时打包 NuGet 包

    被微软收购的 GitHub 越来越好用,拥有大量免费的工具资源和构建服务器资源,再加上私有项目的无限制使用,我有大量的项目都在向 GitHub 迁移。通过 Gi...

    林德熙
  • WPF 使用 Composition API 做高性能渲染

    在 WPF 中很多小伙伴都会遇到渲染性能的问题,虽然 WPF 的渲染可以甩浏览器渲染几条街,但是还是支持不了游戏级的渲染。在 WPF 使用的 DX 只是优化等级...

    林德熙
  • WPF 从零开始开发 dotnet Remoting 程序

    本文告诉大家如何不使用框架,从零开始开发一个 dotnet remoting 程序

    林德熙
  • WPF 通过 dotnet core 发布单文件时 log4net 无法使用

    在使用 dotnet core 版本的 WPF 可以将发布文件打包为一个exe文件,但是此时小伙伴发现 log4net 无法运行,因为 log4net 说找不到...

    林德熙

扫码关注云+社区

领取腾讯云代金券