リソースエディタ

早速 ByteSizeColumn に含まれるリソースを切り離そう。

昨日も説明したが、文字列のリソースの場合は、
.resources ファイルを使って文字列リソースをまとめ、
ResourceManager 経由で読み出した方が効率が良い。

.resources で管理する方法には色々なポリシーがあるが、
ここでは、リソースが必要なクラス毎に、
個別の .resources を作成する方法にしよう。

この方法を使った場合、ファイル数は多くなるが、
クラスとリソースをまとめて扱えるので、
独立性の点で優れていると考えられるからだ。

では、まず .resources を作成しよう。
.resources はバイナリ形式であるため、
IDE を使って作成する場合は、
.resources を直接作成せず、
XML である .resx ファイルを代わりに追加する。

.resx ファイルは、ビルド時に .resources に変換され、
そのままリソースとして埋め込まれる。
なので、IDE では .resx ファイルを編集することになる。

では、「Column」フォルダ内に .resx を追加する。
「追加」⇒「新しい項目の追加」⇒
「アセンブリリソースファイル」を選び、
「ByteSizeColumn」と名前をつける。

ByteSizeColumn.resx ができ、エディタが開くはずだ。
name にキーを、value に値を書き込んでいく。

ByteSizeColumn で使っている文字列は 2 つ。
1 つはカラムのタイトル、もう 1 つは説明だ。
そして、カラム幅である「10」もリソース化しよう。

では、以下のように登録することにする。

    title: 「バイトサイズ」
    description: 「バイト単位のファイルサイズ」
    size: 「10」(System.UInt32)

resx エディタにおいては、既定の型は System.String だ。
そのため、title や description は型の明示は不要である。
size は、符号なしの整数値(uint)にしよう。
ここでは .NET のクラスで規定されているクラスを使うので、
「uint」ではなく「System.UInt32」と指定する。(写真参照)

ByteSizeColumn.resx はこれで OK だ。
次に、ByteSizeColumn.cs を書き換える。

ByteSizeColumn クラスに
ResourceManager 型のフィールドを作成する。
ResourceManager はそこそこ重量のあるクラスなので、
インスタンスフィールドでなく、
クラスフィールド(静的フィールド)として利用しよう。

    // リソース
    private static ResourceManager _resource
            = new ResourceManager(typeof(ByteSizeColumn));

ResourceManager は System.Resources 名前空間にあるので、
「using System.Resources;」を忘れずに。

今回は、ResourceManager のコンストラクタのうち、
Type を取るものを利用している。
このコンストラクタは、受け取った型の名前を基準にして、
.resources リソースを探してくれるのだ。

ByteSizeColumn クラスの名前は、
「LoaferShellEx.Column.ByteSizeColumn」なので、
ResourceManager は、これに「.resources」をつなげた、
「LoaferShellEx.Column.ByteSizeColumn.resources」を探す。

このように、クラスとリソースを同じ名前にしておけば、
ResourceManager の初期化のコードがすっきりする。

次に、ResourceManager を利用するコードだ。

    // カラムの情報を取得
    public override void GetInfo(out SHCOLUMNINFO psci) {

        // まずは既定の実装を呼び、
        base.GetInfo(out psci);

        // 固有分を補正
        psci.vt = VARTYPE.I8;
        psci.fmt = LVCFMT.RIGHT;
        psci.cChars = (uint)_resource.GetObject("size");
        psci.csFlags = SHCOLSTATE.TYPE_INT | SHCOLSTATE.SLOW;
        psci.wszTitle = _resource.GetString("title");
        psci.wszDescription =_resource.GetString("description");
    }

一般的には、GetObject メソッドを使うのだが、
文字列専用として、GetString メソッドが用意されている。
そのため、文字列に関しては GetObject ではなく、
専用の GetString を使った方が効率がいいかもしれない。

整数リソースを取り出すためには、
GetObject を使い、戻り値をキャストする。
リソースを作成するときに厳密に型を指定しているので、
GetObject の戻り値は必ず uint (System.UInt32) だ。
なので、ここでキャストに失敗することは考えなくて良い。

これで、ロジックとリソースを切り離す事ができた。
このクラスはそれほど大きくないのであまり効果はないが、
フォームなどの UI クラスでは大きな効果を発揮するはずだ。