第八章 用户界面(三)
在 F# 中使用 Visual Studio 窗体设计器
到现在,F# 还没有自己的窗体设计器;然而,由于 .NET 具有很强的互操作性,因此,很容易在 F# 中使用由 Visual Studio 设计器创建的窗体。有两种选择:第一,创建一个 F# 库,然后,在自己的 Windows 窗体中调用这个库中的函数;第二;创建一个窗体库,然后,在 F# 应用程序中使用。下面分别讨论这两种方法,并对比它们的优势与不足;示例都是计算斐波那契数列(Fibonacci),如图 8-4。
警告
本书是有关 F# 的,对于书中的主要素材,并不需要任何其他编程语言知识。然而,这一主题,需要有一点点 .NET 编程语言的知识,即,C#;具体来说,在这一节会有两个很短的 C# 程序。当然,如果你愿意,也很容易用 Visual Basic .NET 代码替换 C#。
图 8-4 用 Visual Studio 设计器创建计算斐波那契数列窗体
创建能够在窗体中使用的 F # 库,主要考虑因素是要使库很方便地在窗体中使用。这里,我们创建一个计算斐波那契数列函数,它有一个整数参数,返回的也是整数。这样事情就简单了,因为窗体在使用 .NET 整数类型方面没有任何问题。为了让这个库更有效,还要创建一个斐波那契数列的延迟(lazy)列表,并定义一个函数,取第 n 个数:
module Strangelights.Fibonacci
//an infinite sequence of Fibonacci numbers
let fibs =
(0, 1) |> Seq.unfold
(fun (n0, n1) ->
Some(n0, (n1, n0 + n1)))
// afunction to get the nth fibonacci number
let get n =
Seq.nth n fibs
[
(0,1) |> Seq.unfold
原文这里是(1,1),应该是笔误。
]
很容易在窗体上使用这个函数,只需要在 Visual Studio 窗体项目中引用这个 F# 的 .dll。如果是一个 C# 类,可以通过导入 Strangelights 命名空间,使用模块 Strangelights.Fibonacci,这样 Fibonacci 就好像是 C# 中的一个类。下面的例子演示了如何在 C# 中调用这个函数,并把结果放到控件上。注意,因为这个窗体是用 Visual Studio 2005 创建的,控件定义放在一个单独的源文件中:
using System;
usingSystem.Windows.Forms;
using Strangelights;
namespace CSAPP
{
public partial class FibForm : Form
{
public FibForm()
{
InitializeComponent();
}
private void calculate_Click(object sender, EventArgs e)
{
// convert input toan integer
int n = Convert.ToInt32(input.Text);
// caculate theapropreate fibonacci number
n = Fibonacci.get(n);
// display result touser
result.Text = n.ToString();
}
}
}
[
以下是第二种方法:
]
如果你想从 F# 中使用以 C# 创建的窗体,需要把特定的控件公开为属性;并不需要公开所有的控件,只是那些需要与 F# 进行交互的控件。下面的例子演示如何用 C# 实现;另外,由设计器生成的所有代码都隐藏在一个单独的文件中:
using System;
usingSystem.Windows.Forms;
namespace Strangelights.Forms
{
public partial class FibForm : Form
{
// publicconstructor for the form
public FibForm()
{
InitializeComponent();
}
// expose thecalculate button
public Button Calculate
{
get { return calculate; }
}
// expose theresults label
public Label Result
{
get { return result; }
}
// expose the inputstext box
public TextBox Input
{
get { return input; }
}
}
}
后面的事情就很简单了,从 F# 中引用这个 C# 的 .dll,创建窗体的实例,然后使用。下面例子的代码就是这样做的:
openSystem.Windows.Forms
open Strangelights.Forms
//an infinite sequence of Fibonacci numbers
let fibs =
(0, 1) |> Seq.unfold
(fun (n0, n1) ->
Some(n0, (n1, n0 + n1)))
// afunction to get the nth fibonacci number
let getFib n =
Seq.nth n fibs
let form =
// create a new instance of the form
let temp = new FibForm()
// add an event handler to the form's click event
temp.Calculate.Click.Add
(fun _ ->
// convert input to an integer
let n = int temp.Input.Text
// caculate the apropreate fibonacci number
let n = getFib n
// display result to user
temp.Result.Text <- string n)
temp
Application.Run(form)
可以看到,这两种技术得到的结果是相似的,那么,问题就来了:什么情况下用哪一个更好呢?在 C# 窗体中调用 F# 的问题,是不可避免地要写相当多的 C# 代码,才能把一切连到一起。另外,在 C# 中使用一些F# 类型是很困难,比如,联合类型。基于这两点,我通常是写一个 C# 库,供 F# 使用。在第十四章我们将讨论写 F# 库供其他 .NET 语言使用。