F#でWPF --- Resource、Content、EmbeddedResource

F#でWPFプログラミングをする際に、XamlファイルのBuild Actionをいくつか選ぶことができます。

今回はResource、Content、EmbeddedResource各々でのXamlの読み込み方を記述していきます。

Resource

f:id:any-programming:20170228161625p:plain

WPFにのみ提供されるBuild Actionです。

対象のリソースを実行ファイルに埋め込みます。

リソースを読み込む際は、GetResourceStreamを利用します。

Application.GetResourceStream(Uri("Resource.xaml", UriKind.Relative)).Stream

Xamlファイルを読み込む際は、LoadComponentが利用できます。

Application.LoadComponent(new Uri("Resource.xaml", UriKind.Relative))


Content

f:id:any-programming:20170228161954p:plain

WPFにのみ提供されるBuild Actionです。

対象のリソースを外部ファイルのまま利用します。

"Copy to Output Directory"を"Copy always"か"Copy if newer"にしておくと、ビルドの際に出力ディレクトリにコピーしてくれます。

F#で利用する際には、AssemblyInfo.fsに対象ファイル分、下記を追加する必要があります。(C#では勝手に追加してくれるようです。)

open System.Windows.Resources
[<assembly: AssemblyAssociatedContentFile("Content.xaml")>]

リソースを読み込む際は、GetContentStreamを利用します。

Application.GetContentStream(Uri("Content.xaml", UriKind.Relative)).Stream

Xamlファイルを読み込む際は、LoadComponentが利用できます。

Application.LoadComponent(new Uri("Content.xaml", UriKind.Relative))


EmbeddedResource

f:id:any-programming:20170228162813p:plain

対象のファイルを実行ファイルに埋め込みます。

リソースを読み込む際は、GetManifestResourceStreamを利用します。

Assembly.GetExecutingAssembly().GetManifestResourceStream("Embedded.xaml")

Xamlファイルを読み込む際は、LoadComponentが使えないため、XamlReader.Loadを利用します。

XamlReader.Loadを利用するため、System.Xmlを参照に追加します。

open System.Windows.Markup

let stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Embedded.xaml");
XamlReader.Load(stream)


格納場所

GetManifestResourceNamesを利用することで、アセンブリ内のリソース名一覧が取得できます。

EmbeddedResourceでビルドされたものは、この中に格納されています。

Assembly.GetExecutingAssembly().GetManifestResourceNames() 

このリソースの中に、"アセンブリ名.g.resources"という名前のものがあります。

Resourceでビルドされたものは、さらにこの中に格納されています。

let asm = Assembly.GetExecutingAssembly()
let resources = asm.GetManifestResourceStream(asm.GetName().Name + ".g.resources")
let names = 
    new ResourceReader(resources)
    |> Seq.cast<DictionaryEntry> 
    |> Seq.iter (fun x -> x.Key)


ResourceとEmbeddedResource

WPFで利用するならResourceが基本でいいと思います。

ただ、UserControl内でLoadComponentしたものを、ほかのXaml内で利用しようとすると、Resourceだとデザイナが動作しなくなるため、xamlはEmbeddedResourceのほうがいいかもしれません。

Page

Build ActionにPageというものがあり、これはXamlをBaml(コンパイルされたXaml)に変換するものなのですが、F#では動作させる方法がわかりませんでした。