September 2011

Volume 26 Number 09

F# プログラミング - F# で MVVM アプリケーションをビルドする

Chris Marinos | September 2011

コード サンプルのダウンロード

F# は Visual Studio ファミリでは新しい言語ですが、既に F# のおかげで多くの .NET 開発者が関数型プログラミングの持つ威力を見出しています。F# は、並列プログラミングや非同期プログラミング、データ処理、金融モデルのような複雑な問題を単純化する能力が高い評価を受けていますが、特定の分野のみに適した言語というわけではなく、日常の問題の解決にも力を発揮します。

今回の記事では、F# を使用して実践的な Silverlight アプリケーション、および Windows Presentation Foundation (WPF) の モデル - ビュー - ビューモデル (MVVM: Model-View-ViewModel) アプリケーションをビルドする方法について解説します。F# が複雑なアルゴリズムを単純化することを得意とする理由となっている概念は、ビュー モデルの形式的な部分を減らすためにも使えるのがわかります。また、F# の既知の非同期ワークフローを GUI 設定にどのように適用できるかも確認します。最後に、F# で MVVM アプリケーションを構造化する 2 つの一般的アプローチと、それぞれのメリットおよびデメリットについて紹介します。この記事を読み終えるころには、F# は特殊な問題に使えるツールとしてだけでなく、単純なアプリケーションのコードをさらに読みやすく、書きやすく、管理しやすくする F# の使用法を習得できます。

形式的な部分を減らす

おそらく、F# を GUI アプリケーションの操作に使用するには適していない言語と考えているのではありませんか。と言うのも、関数型言語は副作用を重視しないため、Silverlight や WPF のようなフレームワークは副作用であふれ返ってしまいます。ビュー モデルには、関数型スタイルに切り替えるメリットがあるほど複雑なロジックは含まれていないと思われるかもしれません。関数型プログラミングは、MVVM などの設計パターンの操作を難しくするパラダイム シフトが必要になると考えていませんか。実は、F# によるビュー モデルとモデルの構築は簡単で、C# とほとんど変わりません。また、ビュー モデルは、F# が形式的なコード (定型コード) を減らすところを確認できる格好の例でもあります。C# プログラミングに慣れている方は、F# がコードの中で重要な情報の比率をどれだけ効果的に高めるかをご覧いただけば、驚かれること請け合いです。

図 1 は、名前、ジャンル、および評価 (省略可能) のフィールドを含む、簡単な動画モデルの F# コードです。F# の option 型について馴染みのない方は、C# の NULL 値許容型がより強力になり、表現力が高くなったものと考えてください。option 型は、動画モデルの評価の有無を示すための自然な方法ですが、データ バインドに関する問題を引き起こします。たとえば、None (NULL 値許容型では null 値に相当) に設定されている option 型から値を取得しようとすると、例外がスローされます。また、option 型 が None に設定されている場合、Rating にバインドされるコントロールを非表示にすることを考えるかもしれませんが、残念ながら、WPF または Silverlight が Rating の値を取得しようとして例外が発生すると、表示のバインドは正しく実行されません。これは、評価に関する表示ロジックを追加するビュー モデルが必要となる簡単な例の 1 つです。

図 1 簡単な動画モデル

type Movie = {
  Name: string
  Genre: string
  Rating: int option
}

図 2 は、この表示ロジックの例を備えたビュー モデルです。評価が設定されている場合はその値をビューに渡し、評価が設定されていない場合は既定値の 0 を渡します。この簡単なロジックによって、Rating が None の場合に例外がスローされなくなります。また、このビュー モデルは、表示のバインドを処理するために 2 つ目のプロパティを公開します。このメソッドは単に、Rating が Some の場合に true を返し、None の場合に false を返します。このビュー モデルのロジックは単純ですが、例として注目すべきところはロジックではありません。注目すべき点は、F# がビュー モデルの定義を簡潔に表しているところです。C# では、ビュー ロジックを複雑にする定型コードであふれ返ることが多く、楽なのはコンパイラだけです。

図 2 評価の表示ロジックを備えた動画のビュー モデル

type MovieViewModel(movie:Movie) =
  member this.Name = movie.Name
 
  member this.Genre = movie.Genre
 
  member this.Rating =
    match movie.Rating with
    | Some x -> x
    | None -> 0
 
  member this.HasRating = movie.Rating.IsSome

図 3 は、同じビュー モデルを C# で記述したものですが、形式的なコードが劇的に増えています。C# では、ビュー モデルを表現するために、F# の約 4 倍のコードが使われています。増加した原因の大半は中かっこですが、型の注釈、return ステートメント、アクセシビリティ修飾子などの重要な項目すらも、ビュー モデルをカプセルするために作成しているロジックを理解しにくくしています。F# は、このような余分なコードを減らして、重要なコードにのみ集中できるようにします。関数型プログラミングは、簡単すぎたり、読みにくかったりする場合は評判がよくありませんが、この例では、F# が簡潔さのために明瞭さを犠牲にしていないのは明らかです。

図 3 動画の C# ビュー モデル

class MovieViewModelCSharp
{
  Movie movie;
 
  public MovieViewModelCSharp(Movie movie)
  {
    this.movie = movie;
  }
 
  public string Name
  {
    get { return movie.Name; }
  }
 
  public string Genre
  {
    get { return movie.Genre; }
  }
 
  public int Rating
  {
    get
    {
      if(OptionModule.IsSome(movie.Rating))
      {
        return movie.Rating.Value;
      }
      else
      {
        return 0;
      }
    }
  }
 
  public bool HasRating
  {
    get
    {
      return OptionModule.IsSome(movie.Rating);
    }
  }
}

前の例では、ビュー モデルを記述するときに F# がもたらすメリットについて示しましたが、F# は MVVM アプリケーションのビュー モデルに共通する問題も解決します。たとえば、ドメインが変わり、モデルも更新する必要があるとしましょう。Genre は、単一の文字列ではなくタグのリストになります。モデル コードでは、

Genre: string

という行を、次のように変更します。

Genre: string list

しかし、このプロパティは、ビュー モデルを通じてビューに伝達していたため、ビュー モデルの戻り値の型も変更しなければなりません。このため、C# ではビュー モデルを手作業で変更する必要がありますが、F# では型の推論により自動的に行われます。F# の型の推論について詳しくない方は驚かれるかもしれませんが、これはまさに誰もが求める動作です。Genre には表示ロジックがまったく必要ないため、ビュー モデルは単にこのフィールドを変更しないでビューに渡します。つまり、ビュー モデルのプロパティの戻り値の型については、モデルのプロパティの戻り値の型と一致している限り、気に留める必要はありません。F# コードがその状態を正確に処理します。F# は依然として静的な型指定も可能なため、静的な型指定を行うと、ビュー モデルまたはモデル (XAML を除く) におけるフィールドの誤使用は、コンパイル エラーになることに注意してください。

既存の資産を活用する

図 1図 2 のビュー モデルは、モデルに表示ロジックを追加する役割しかないため、一方向のバインドのみをサポートしていました。このように単純なビュー モデルは、形式的なコードを減らす F# の能力を示すのには有効ですが、ビュー モデルでは通常、変更可能なプロパティに INotifyPropertyChanged を実装して、双方向のバインドをサポートする必要があります。一般に、C# の MVVM アプリケーションには、INotifyPropertyChanged やビュー モデルに関するその他の懸念事項の実装を容易にするために、ビュー モデルの基本クラスを含めます。この動作を F# で再実装する必要はありません。コードを書き直さなくても、F# では、既存の C# ビュー モデルの基本クラスを再利用できます。

F# で ViewModelBase クラスを使用する例を図 4 に示します。ViewModelBase は、Brian Genisio (houseofbilz.com、英語) が作成した C# の基本クラスで、ここではこれをすべての C# および F# ビュー モデルに使用しています。図 4 では、基本クラスが、INotifyPropertyChange の実装に使用する base.Get 関数および base.Set 関数を提供します。ViewModelBase は、C# の動的プログラミング機能を使用して規約ベースのコマンド生成もサポートします。F# は別の .NET 言語とも簡単に相互運用できるよう設計されているため、どちらの機能も F# ビュー モデルでシームレスに動作します。ViewModelBase の使い方の詳細については、viewmodelsupport.codeplex.com (英語) でソースを確認してください。

図 4 C# ViewModelBase クラスからの継承

type MainWindowViewModel() =
  inherit ViewModelBase()
 
  member this.Movies
    with get() =
      base.Get<ObservableCollection<MovieViewModel>>("Movies")
 
    and set(value) =
      base.Set("Movies", value)

非同期にする

非同期操作とキャンセル可能な操作のサポートも、ビュー モデルとモデルの一般的な要件です。従来の手法を使用してこの要件を満たすと、アプリケーションが非常に複雑になりますが、F# にはこの作業を簡略化する強力な非同期プログラミング機能があります。図 5 は、動画データを取得するための Web サービスへの非同期呼び出しです。サーバーからの応答は、動画モデルのリストとして解析します。このリスト内のモデルは、その後ビュー モデルにプロジェクションし、ObservableCollection に追加します。このコレクションは、ユーザーに結果を表示するために、ビューのコントロールにデータ バインドします。

図 5 動画処理についての Web 要求のサンプル

member this.GetMovies() =
  this.Movies <- new ObservableCollection<MovieViewModel>()
 
  let response = webClient.DownloadString(movieDataUri)
 
  let movies = parseMovies response
 
  movies
  |> Seq.map (fun m -> new MovieViewModel(m))
  |> Seq.iter this.Movies.Add

このコードを非同期に実行するよう変換するには、従来の非同期ライブラリを使用して制御フローを完全に見直す必要があります。コードを、非同期呼び出しごとにコールバック メソッドに分割します。これが原因で複雑さが増し、コードが読みにくくなるうえ、コードのメンテナンスに関するオーバーヘッドも大幅に増加します。F# モデルでは、このような問題は生じません。F# では、コードの構造に影響を与えないちょっとした変更を行うだけで、非同期動作を実装できます (図 6 参照)。

図 6 動画処理についての非同期 Web 要求

member this.GetMovies() =
  this.Movies <- new ObservableCollection<MovieViewModel>()
 
  let task = async {
    let! response = webClient.AsyncDownloadString(movieDataUri)
 
    let movies = parseMovies response
 
    movies
    |> Seq.map (fun m -> new MovieViewModel(m))
    |> Seq.iter this.Movies.Add
  }
 
  Async.StartImmediate(task)

図 6 の例では、非同期に実行される同じコードを示します。Web サービスを呼び出して結果のリストを更新するコードを非同期ブロックで囲むことから変更に着手します。ステートメントを非同期実行するよう F# に指示するために、let! キーワードをこのブロック内で使用します。この例では、let! が Web 要求を非同期に行うよう Web クライアントに指示しています。F# は、このプロセスを容易にするために、WebClient の拡張として AsyncDownloadString メソッドを提供します。最後の変更は、Async.StartImmediate の呼び出しです。これにより、現在のスレッドで非同期ブロックが開始されます。GUI スレッドでの実行によって、バックグラウンド スレッドで GUI を更新しようとすると発生する厄介な例外が回避され、非同期動作により、Web 要求が行われている間に GUI が処理を停止しないようになります。

この動作を非同期に実行するよう変更するためには、それほど多くのコードを追加する必要はありませんが、おそらく重要なのは、コードの構造を変えないように変更することです。最初にコードを記述するとき、今後非同期に実行する可能性を考えて設計する必要はありません。プロトタイプを作成するときに同期コードを記述しても、後から必要に応じて簡単に非同期に変換できます。この柔軟さによって、開発にかかる時間を節約できるため、クライアントからの変更要求に迅速に対応してクライアントに好印象を与えることができます。

C# の最新の開発状況を理解していれば、このスタイルの非同期プログラミングはおなじみでしょう。なぜなら、C# に新しく導入された非同期機能は、F# のモデルに深く基づいているためです。C# の非同期機能は Community Technology Preview (bit.ly/qqygW9、英語) から利用できますが、F# の非同期機能は現在運用環境で使用できます。非同期ワークフローは、F# のリリース当初から使用可能だったため、F# を学習することで C# 開発者としてのレベルが上がる理由となる格好の例です。

C# と F# のモデルは似ていますが、異なる部分もあります。その代表的な例がキャンセルです。図 7 のコードでは、GetMovies 関数にキャンセル処理を追加しています。ここでも、変更する必要があるのはほんの少しです。ワークフローにキャンセルをサポートさせるためには、CancellationTokenSource を作成して、そのキャンセル トークンを Async.StartImmediate 関数に渡します。図 7 では、未処理の操作をキャンセルするために GetMovies 関数の先頭に追加のセットアップ コードをいくつか含めています。これで、識別可能なコレクションが複数回更新されるのを避けることができます。また、ワークフローの各実行においてCancellationToken が確実に一意になるように、関数へのすべての呼び出しで新しい CancellationTokenSource を発行します。

図 7 F# でのキャンセル

let mutable cancellationSource = new CancellationTokenSource()
 
member this.GetMovies() =
  this.Movies <- new ObservableCollection<MovieViewModel>()
  cancellationSource.Cancel()
  cancellationSource <- new CancellationTokenSource()
 
  let task = async {
    let! response = webClient.AsyncDownloadString(movieDataUri)
 
    let movies = parseMovies response
 
    movies
    |> Seq.map (fun m -> new MovieViewModel(m))
    |> Seq.iter this.Movies.Add
  }
 
  Async.StartImmediate(task, cancellationSource.Token)

C# のモデルでは、キャンセルをサポートするためには関数呼び出しのチェーンに CancellationToken を次々と手動で渡す必要があります。ただしこれは、多くの関数シグネチャにさらなる引数を追加しなくてはならない可能性を生むため、煩わしい変更です。また、キャンセルが要求されているかどうか知るため、CancellationToken を手動でポーリングする必要もあります。F# モデルでは、実行する作業はずっと少なくなります。非同期ワークフローが let! に遭遇すると、StartImmediate 呼び出しで受け取った CancellationToken を確認します。トークンが有効であれば、ワークフローは通常どおり実行されます。トークンが無効であれば、操作は実行されず、残りのワークフローも実行されません。キャンセルの暗黙的な処理は便利な機能ですが、これは強制ではありません。ワークフローの CancellationToken を手動でポーリングする必要がある場合は、Async.CancellationToken プロパティを使用すれば CancellationToken にアクセスできます。

let! token = Async.CancellationToken

F# で MVVM アプリケーションを構造化する

F# がビュー モデルとモデルを強化する実用的な方法を見てきました。ここからは、Silverlight アプリケーションや WPF アプリケーションに F# を組み込む方法について説明します。C# で MVVM アプリケーションを構造化する方法はたくさんあります。これは F# でも変わりません。今回は、2 つのアプローチを紹介します。all-F# (すべてを F# で実現する) アプローチと、ビューに C# を使用してビュー モデルとモデルに F# を使用する多言語アプローチです。いくつかの理由により、多言語アプローチをお進めします。最初の理由は、F# チームが推奨するアプローチだからです。2 つ目は、C# における WPF と Silverlight のツール サポートは、F# のサポートよりもずっと強力だからです。最後に、このアプローチにより、F# を既存のアプリケーションに組み込むことができ、MVVM アプリケーションで F# を低リスクで使用するのが可能になるためです。

all-F# アプローチは、1 つの言語でアプリケーションを記述できるため便利ですが、いくつか制限があります。後ほど、これらの一般的な制限のいくつかを取り除く方法について説明しますが、小さなアプリケーションでない限り、得られるメリットは回避策に見合うものではありません。多言語アプローチでは、ビュー コードに F# を使用することが求められているわけではありませんが、MVVM アプリケーションの構造を適切にするには、ビューのロジックをごく少量にすべきです。さらに、ビュー ロジックは副作用が大きくなる傾向にあり、命令型の性質を持つので、必要に応じてビュー ロジックを記述するのに適した言語は C# と言えます。

多言語アプローチを使用する

多言語アプローチを使用して MVVM アプリケーションを作成するのは実に簡単です。まず、WPF アプリケーション プロジェクト テンプレートを使用して、C#で 新しい WPF プロジェクトを作成します。このプロジェクトは、アプリケーションに必要なビューと分離コードを用意します。次に、ビュー モデル、モデル、およびその他のビュー以外のコードを保持するために、ソリューションに新しい F# ライブラリ プロジェクトを追加します。最後に、C# WPF プロジェクトから F# ライブラリ プロジェクトへの参照を追加します。多言語アプローチを開始するために必要なのは、この設定だけです。

F# は、あらゆる .NET 言語とスムーズに相互運用できるように設計されているため、C# ビュー モデルに従来使用していたメソッドを使って C# のビューに F# ビュー モデルを結合することが可能です。簡潔さのために、分離コードを使用する例を紹介します。まず、F# プロジェクトの名前を Module1.fs から MainWindowViewModel.fs に変更して、簡単なビュー モデルを作成したら、図 8 のコードをビュー モデルに設定します。次に、図 9 のコードを使用して C# のビューに F# ビュー モデルを接続します。ビュー モデルが F# で記述されているのを知らなかったら、きっと C# ビュー モデルとの違いはわからないでしょう。

図 8 ダミーの F# ビュー モデル

namespace Core.ViewModels
 
type MainWindowViewModel() =
  member this.Text = "hello world!"
Figure 9 Connecting the F# View Model to the C# View
protected override void OnInitialized(EventArgs e)
{
  base.OnInitialized(e);
 
  this.DataContext = new MainWindowViewModel();
}

図 9 F# ビュー モデルの C# のビューへの接続

protected override void OnInitialized(EventArgs e)
{
  base.OnInitialized(e);
 
  this.DataContext = new MainWindowViewModel();
}

MainWindow.xaml にテキスト ボックスを追加して、Binding を Text に設定します。ここでも、まるでアプリケーションが C# だけで記述されているようにすべてが動作します。アプリケーションを実行し、おなじみの "Hello World!" を表示してみて、バインドが機能していることを確認してください。

all-F# アプローチ

前述のように、使いやすさと柔軟さから、多言語アプローチがお勧めです。ただし、トレードオフのため、all-F# アプローチについても説明します。Visual Studio 2010 には、Silverlight ライブラリを F# で作成するためのテンプレートが付属していますが、F# で WPF アプリケーションまたは Silverlight アプリケーションを作成するためのテンプレートは含まれていません。さいわい、このようなテンプレートはインターネットからダウンロードできます。最初に使うものとしては、Daniel Mohl (bloggemdano.blogspot.com、英語) が作成したテンプレートをお勧めします。このテンプレートには、完全なアプリケーションの構造を確認できるサンプル アプリケーションが含まれているためです。ここでは学習のために、ゼロから WPF の F# アプリケーションをビルドする方法を示しますが、実際にはオンラインのテンプレートを使用することをお勧めします。

all-F# アプローチの手始めとして、FSharpOnly という F# アプリケーション プロジェクトを新しく作成します。プロジェクトの作成が完了したら、プロジェクトのプロパティを開いて、[出力の種類] を [Windows アプリケーション] に変更します。次に、PresentationCore、PresentationFramework、PresentationUI、System.Xaml、および WindowsBase への参照を追加します。さらに、プロジェクトに App.xaml、MainWindow.xaml というファイルを追加して、各ファイルの [ビルド アクション] を [Resource] に設定します。既定では、F# には XAML ファイルを生成するための項目テンプレートはありませんが、.xaml という拡張子を付けた一般的なテキスト ドキュメントのテンプレートを使用できます。これらの XAML ファイルに、それぞれ図 10図 11 のコードを設定します。App.xaml と MainWindow.xaml は、標準の C# WPF アプリケーションと同じ機能を実行します。

図 10 App.xaml ファイルのサンプル

<Application
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="assembly=FSharpOnly"
  StartupUri="MainWindow.xaml">
</Application>
Figure 11 A Sample MainWindow.xaml File
<Window
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="assembly=FSharpOnly"
  Title="Sample F# WPF Application Written Only in F#"
  Height="100"
  Width="100" >
  <Grid>
    <TextBlock>Hello World!</TextBlock>
  </Grid>
</Window>

図 11 MainWindow.xaml ファイルのサンプル

<Window
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="assembly=FSharpOnly"
  Title="Sample F# WPF Application Written Only in F#"
  Height="100"
  Width="100" >
  <Grid>
    <TextBlock>Hello World!</TextBlock>
  </Grid>
</Window>

Program.fs に、図 12 のコードを追加します。このコードは、App.xaml ファイルを読み込み、アプリケーションを実行します。

図 12 Program.fs のサンプル

open System
open System.Windows
open System.Windows.Controls
open System.Windows.Markup
 
[<STAThread>]
[<EntryPoint>]
let main(_) =
  let application = Application.LoadComponent(new Uri("App.xaml", UriKind.Relative)) :?> Application
  application.Run()

アプリケーションを実行すると "Hello World!" が表示されます。この時点では、多言語アプローチと同じように、好みの手法でモデルにビュー モデルを接続できます。

all-F# アプローチで直面する可能性がある問題の 1 つには、静的リソースが関係します。App.xaml は、C# WPF プロジェクトでは通常 ApplicationDefinition として定義しますが、all-F# アプローチでは Resource として定義します。これが原因で、App.xaml で定義している静的リソースを別の XAML ファイルから参照すると、その静的リソースの解決が実行時に失敗します。回避策は簡単で、App.xaml ファイルの [ビルド アクション] を [ApplicationDefinition] に変更して、デザイナーを再度読み込みます。これにより、デザイナーが App.xaml 内のリソースを認識して、ビューを正しく読み込みます。ただし、アプリケーションをビルドするときは App.xaml の [ビルド アクション] を [Resource] に戻さないと、ビルド エラーが発生します。

all-F# アプローチでは、分離コードの動作も異なります。F# は部分クラスをサポートしないため、XAML ファイルは .fs 分離コード ファイルに関連付けられません。C# ではこれが可能です。MVVM アプリケーションでは分離コードの使用をできる限り避けることをお勧めしますが、問題を解決するのに分離コードが最も実用的な方法である場合もあります。F# で従来の分離コードがサポートされないことに対処する方法はいくつかあります。最も簡単なのは、単純に F# でビュー全体を構成する方法です。このアプローチは簡単ですが、XAML の宣言的な性質を失うため、煩わしくなることもあります。別のアプローチとして、アプリケーションを構成するときに視覚的な要素にフックする方法もあります。このアプローチの例を図 13 に示します。

図 13 UI 要素にフックするように変更した Main.fs

let initialize (mainWindow:Window) =
  let button = mainWindow.FindName("SampleButton") :?> Button
  let text = mainWindow.FindName("SampleText") :?> TextBlock
 
  button.Click
  |> Event.add (fun _ -> text.Text <- "I've been clicked!")
 
[<STAThread>]
[<EntryPoint>]
let main(_) =
  let application = Application.LoadComponent(new Uri("App.xaml", UriKind.Relative)) :?> Application
 
  // Hook into UI elements here
  application.Activated
  |> Event.add (fun _ -> initialize application.MainWindow)
 
  application.Run()

F# で部分クラスがサポートされないことにより、ユーザー コントロールも使いにくくなります。XAML ではユーザー コントロールを簡単に作成できますが、アセンブリに部分クラスの定義がないため、別の XAML ファイルのユーザー コントロールを参照することはできません。これには、図 14 のように XamlLoader クラスを作成して対処できます。

図 14 F# でユーザー コントロールを作成するための XamlLoader クラス

type XamlLoader() =
  inherit UserControl()
 
  static let OnXamlPathChanged(d:DependencyObject) (e:DependencyPropertyChangedEventArgs) =
    let x = e.NewValue :?> string
    let control = d :?> XamlLoader
 
    let stream = Application.GetResourceStream(new Uri(x, UriKind.Relative)).Stream
    let children = XamlReader.Load(stream)
    control.AddChild(children)
 
  static let XamlPathProperty =
    DependencyProperty.Register("XamlPath", typeof<string>, typeof<XamlLoader>, new PropertyMetadata(new PropertyChangedCallback(OnXamlPathChanged)))
 
  member this.XamlPath
    with get() =
      this.GetValue(XamlPathProperty) :?> string
           
    and  set(x:string) =
      this.SetValue(XamlPathProperty, x)
 
  member this.AddChild child =
    base.AddChild(child)

このクラスにより、依存関係プロパティを使用して XAML ファイルへのパスを設定できます。このプロパティを設定すると、XamlLoader はファイルから XAML を解析して、ファイルで定義されているコントロールをその子コントロールとして追加します。XAML では、XamlLoader を次のように使用します。

<local:XamlLoader XamlPath="UserControl.xaml" />

XamlLoader の回避策により、多言語アプローチに戻らずにユーザー コントロールを作成できますが、C# でビューを作成すれば発生することのない障害ではあります。

まとめ

F# の使用例を見てきましたが、F# が実用的なアプリケーションを記述するための言語であることは明白です。F# は、コードの形式的な部分を減らし、ビュー モデルとモデルを読みやすくし、メンテナンスを容易にします。また、複雑な問題をすばやく柔軟に解決するために、非同期プログラミングなどの機能を使用する方法についても紹介しました。最後に、F# で MVVM アプリケーションを構造化する 2 つの主な方法の概要を示しました。加えて、それぞれのアプローチにおけるトレードオフも紹介しました。これで、Silverlight アプリケーションや WPF アプリケーションで関数型プログラミングの能力を引き出す準備ができました。

次回 Silverlight アプリケーションまたは WPF アプリケーションを記述するときは、F# を試してみてください。さらに、多言語アプローチを使用して F# で既存のアプリケーションの一部を記述してみてください。記述およびメンテナンスする必要のあるコード量が大幅に減ることがすぐにおわかりいただけます。また、all-F# アプローチを実際に使ってください。WPF、Silverlight、または F# について知らなかった部分を確実に学べるはずです。次に何をするにしても、F# でプログラミングを行う楽しさを知れば、C# に対する見方が変わります。

Chris Marinos は、F# に力を注いでいるソフトウェア コンサルタントおよび Microsoft MVP です。ミシガン州のアナーバーに拠点を置く SRT Solution 社に勤務し、F# と関数型プログラミングに情熱を注いでいます。これらのトピックやアナーバー周辺についてのおもしろいトピックについては、彼の講演を聞くか、ブログ (chrismarinos.com、英語) をチェックしてください。

この記事のレビューに協力してくれた技術スタッフの Cameron Frederick および Daniel Mohl に心より感謝いたします。