2016年4月13日水曜日

[WPF C#] リソースについて(まとめ)

.NETやWPFのリソースについてです。わかっている人にはどってことないの話です。どちらかと言うと初心者向けです。ここでいうリソースというのは、文字列や画像、ファイルなどを実行モジュールに埋め込んで、実行に読み込むための仕組みということです。
Visual Studio 2015の操作方法で説明します。

Win32リソース

おそらく、.NETでの開発では、この仕組みは利用することがないと思いますが、念のため。Win32リソースとは、実行モジュール(.exeや.dll)にリソースを埋め込むもので、かつての方法では、.rcファイルから、.resファイルをリソースコンパイラでコンパイルして、リンク時に埋め込みます。詳細については割愛します。

アセンブリマニフェストリソース

この仕組みは、アセンブリ(.NETで開発した.exeや.dll)にファイルを埋め込むものです。ただし、一般的にはこの方法を利用することはあまりないと思います。なぜなら、もっと便利な方法があるからです。

定義方法
ソリューションエクスプローラーで、埋め込もうとするファイルのプロパティを表示します。プロパティにビルドアクションの項目を「埋め込みリソース」に設定します。この方法で埋め込めるのはファイルだけです。あと、出力ディレクトリにコピーの項目は「なし」でよいです。
コードからの利用方法
まず、System.Reflection.Assembly assembly = this.GetType().Assembly;などの方法で、実行中のアセンブリを取得します。アセンブリから、埋め込まれているリソースのストリームを取得します。
System.IO.Stream stream = assembly.GetManifestResourceStream(resouceName);
ここでresouceNameというのは、<名前空間>.<アセンブリモジュールからの相対パス名(区切りは".")>です。
例えば、MyAppという名前空間でプロジェクトの中にResoucesというフォルダを作って、そのなかにMyApp.icoというファイルを埋め込んだ時には、リソース名は、"MyApp.Resources.MyApp.ico"となります。

.resxファイルを使ったリソース

おそらく、.NETでの開発でのリソースといえば、この方法のことをいうことが多いようです。Visual Stuioで.NETのプロジェクトを作成すると、Propertiesというフォルダの中に、Resources.resxというファイルが作成されるはずです。
リソースとしては、ファイル以外にも文字列や画像なども組み込むことができます。.resxファイルはビルド時に.resourcesファイルに変換されて、アセンブリのファイルに組み込まれます。これは、Win32リソースに似ていますが、全くの別物です。また、この仕組みは、アセンブリマニフェストリソースによって実現されており、上記のResources.resxの場合、アセンブリマニフェストリソースでのリソース名は、<名前空間>.Properties.Resources.resourcesとなります。なお、Resources.resx以外のファイルをプロジェクトに追加して利用することも可能です。

定義方法
通常、ソリューションエクスプローラーで、.resxファイルを開くと定義画面が表示されます。もし表示されなかったら、ファイルのプロパティを開いて、カスタムツールの項目が"ResXFileCodeGenerator"になっているか確認してください。この画面の操作方法については、ヘルプ等を参照してください。
コードから利用方法
同一名前空間からの利用であれば、Properties.Resources.<プロパティ名>というオブジェクトが利用できます。型は、定義された適切なものになっています(例:文字列→string)。場合によっては、global::<名前空間>.Properties.Resources.<プロパティ名>で参照しないと見れないかもしれません。

WPF用のリソース

WPFのプロジェクトでは、アセンブリマニフェストリソースに似たリソースが利用できます。これで定義できるのはファイルのみです。ちなみにこの仕組みもアセンブリマニフェストリソースで実現されており、アセンブリマニフェストでのリソース名は、"<アセンブリ名>.g.resources"となります。

定義方法
ソリューションエクスプローラーで、プロパティを開くとビルドアクションに"Resource"という項目があるので、それを選びます。ただし、この項目はWPF専用ということになっています。なお、この場合も、出力ディレクトリにコピーは「なし」です。
コードから利用方法
WPFのAPIからのファイルへのアクセスは基本Uriオブジェクトから参照するので、Uri uri = new Uri(pathname, UriKind.Relative);のようにUriオブジェクトを作成します。pathnameは、アセンブリファイルの相対パスになるのですが、先頭に"/"をつけるのが普通なようです。例えば、Resourcesのフォルダの中にMyApp.icoというファイルを追加して、ビルドアクションを"Resource"にした時には、pathnameは"/Resources/MyApp.ico"となります。
XAMLからの利用方法
XAMLから参照する場合には、上記でいうところのpathnameを設定すればよいです。
余談かもしれませんが、WPFのアプリケーションでアイコンを設定する場合、この方法が良いかと思います。上記の例でアイコンをリソースとして組み込んだ場合、プロジェクトのプロパティでアイコンの設定のところで、コンボボックスにこのファイルが選べるようになっているので、それを選べばよいです。

ビルドアクションの「コンテンツ」

この方法は、リソースとは言わないようですが、実行時にファイルを読み込めるという意味では、いわゆるリソースとして使えます。これは、実行モジュールとともにファイルをコピーするものです。そのため、利用者に普通に見られてしまう可能性があります。

定義方法
ビルドアクションを「コンテンツ」に設定します。この場合には、出力ディレクトリにコピーは「なし」以外を選んでください。
コードから利用方法
WPFアプリケーションででなくても、利用できるのですがWPFだと簡単にできるので、その方法を書きます。
WPFのリソースと同様にUriでファイルを指定するのですが、通常Uri uri = new Uri(uri, UriKind.Absolute);のように指定します。uriは"pack://application:,,,/<実行モジュールからの相対パス>"で指定します。先程と同じように"Resources/MyApp.ico"というファイルをプロジェクトに追加して、ビルドアクションをコンテンツにした場合には、"pack://application:,,,/Resources/MyApp.ico"となります。ただし、場合によっては、"pack://application:,,,/<アセンブリ名>;component/<実行モジュールからの相対パス>"というようにしないと参照できない場合があるようです。上記の例で、アセンブリ名が"MyApp"とすれば、"pack://application:,,,/MyApp;component/Resources/MyApp.ico"となります。
XAMLからの利用方法
WPFのリソースと同様に、上記でいうところのuriを設定すればよいです。

XAMLのリソース

これは、いわゆるリソースではありません。XAMLのリソースというのは、ResourceDirectoryに追加されるものをいうようです。よく使われるのは、Application.ResourceやWindow.Resourcesを使ってキーとともになんだかのオブジェクトと追加して、キーからそのオブジェクトを利用するパターンです。このリソースの詳細については、"Static Resource"や"Dynamic Resource"というキーワードで検索してください。