C#でリソースの.icoアイコンをコードで設定する方法|WinFormsのProperties.ResourcesとWPF変換まで解説

WinFormsで作ったC#アプリのフォームアイコンを、プロジェクトに追加した「.ico」リソースからコードで切り替えたい。ところが、ComponentResourceManagerやnew Icon(...)で読み込もうとしても、リソースの種類や参照先がズレていて意図どおり動かないケースがよくあります。この記事では、確実に動く設定手順(WinForms前提)と、WPFでbyte[]になって詰まる場合の実践的な対処法までまとめます。

目次

C#の「リソース」には複数の置き場所がある

最初につまずきやすいのが、「同じ“リソース”という言葉でも、どこに格納したかで読み出し方が変わる」という点です。あなたが追加した.icoが、どの種類のリソースとして登録されているかで、正しいコードが変わります。

リソースの種類主な保存場所代表的な参照方法向いている用途落とし穴
プロジェクト リソース(強く型付け)Properties/Resources.resxProperties.Resources.名前アプリ全体で使う画像・音・アイコン追加方法によってはIconではなくbyte[]になる
フォーム固有のリソース(デザイナー用)TLS_FormMain.resxComponentResourceManagerフォームのデザイナーが生成する既定値キー名が$this.Iconなど独特。拡張子付きではない
埋め込みリソース(Embedded Resource)任意のファイル(Build Action)Assembly.GetManifestResourceStream独自読み込み・ライブラリ配布完全修飾名(名前空間)が必要。指定を間違えると常にnull
コンテンツ(Content / Copy)実行ファイルの横などnew Icon("path")差し替え可能な外部ファイル配布時にファイル同梱が必要。パス問題が起きやすい

この記事で主に扱うのは、最もラクで事故が少ない「プロジェクト リソース(Properties.Resources)」です。WinFormsでフォームのアイコンを変えるだけなら、ここに寄せるのが王道です。

WinFormsの結論:フォームのIconは Properties.Resources から1行で設定できる

WinFormsで「フォーム(ウィンドウ)の左上やタスクバーに出るアイコン」を変えたいだけなら、答えはシンプルです。

  • .icoをプロジェクトのリソースに追加する
  • this.IconにProperties.Resources.リソース名を代入する

手順:.icoを「リソース」として追加する

Visual Studioの操作イメージは次のとおりです(WinForms前提)。

  • プロジェクトのプロパティを開く
  • 「リソース」タブを選ぶ
  • 「リソースの追加」→「既存のファイルの追加」→.icoを選択
  • 登録されたリソース名(例:TLS_Icon_Green)を確認

ここで重要なのは「リソース名」です。コードで参照するのはファイル名(TLS_Icon_Green.ico)ではなく、リソースとして登録された“名前”(TLS_Icon_Greenなど)になります。

コード:フォームのアイコンを設定する

フォームのコンストラクタでInitializeComponent()の後に、次の1行を書くだけでOKです。

public partial class TLS_FormMain : Form
{
    public TLS_FormMain()
    {
        InitializeComponent();

        // リソース名が Test2 の場合
        this.Icon = Properties.Resources.Test2;

        // リソース名が TLS_Icon_Green の場合
        // this.Icon = Properties.Resources.TLS_Icon_Green;
    }
}

Properties.Resources.リソース名がSystem.Drawing.Iconとして生成されていれば、これだけでフォームアイコンは変更できます。WinFormsの基本はここです。

実運用のコツ:共有リソースをそのまま渡さず、Cloneして渡す

実務でアイコンを切り替える場合、同じリソースを複数フォームで使い回すことがあります。そのときに地味に効いてくるのが「リソースを直接渡すと、フォーム破棄時のDisposeの影響を受ける可能性がある」という点です(環境や使い方で問題化します)。

安全側に倒すなら、フォームに渡すときだけクローンして使うのが無難です。

// 破棄の影響を避けたい場合はCloneして渡す
this.Icon = (Icon)Properties.Resources.TLS_Icon_Green.Clone();

「アイコンを頻繁に切り替える」「複数フォームで同じアイコンを共有する」場合ほど、この書き方にしておくと後でハマりにくくなります。

状態に応じてアイコンを切り替える例(通信状態・稼働状態など)

例えば、接続状態に応じてアイコンを切り替えたい場合は次のようにまとめると読みやすいです。

private void UpdateWindowIcon(bool isConnected)
{
    this.Icon = isConnected
        ? (Icon)Properties.Resources.TLS_Icon_Green.Clone()
        : (Icon)Properties.Resources.TLS_Icon_Gray.Clone();
}

WinFormsのアイコン切り替えは「this.Iconに代入する」だけなので、状態管理の設計(いつ、どのイベントで更新するか)に注力できます。

試したコードが動かなかった理由と、ハマりポイントの整理

提示されていた2パターンは、どちらも「コード自体が大きく間違っている」というより、参照しているリソースの種類が想定と一致していないことが原因になりがちです。

パターン1:ComponentResourceManagerで "TLS_Icon_Green.ico" を探しても見つからない

System.ComponentModel.ComponentResourceManager resources2 =
    new System.ComponentModel.ComponentResourceManager(typeof(TLS_FormMain));
this.Icon = (Icon)(resources2.GetObject("TLS_Icon_Green.ico"));

ComponentResourceManager(typeof(TLS_FormMain))が主に見るのは、フォームのデザイナーが使う「フォーム固有のresx(例:TLS_FormMain.resx)」です。ここに登録されていないキーを指定すると当然取れません。

さらに、キー名の付け方も誤解されやすいポイントです。WinFormsのフォームデザイナーがアイコンを設定している場合、キーは次のように$this.Iconになっていることが多いです。

// デザイナーが生成する典型例(参考)
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));

つまり、「ファイル名(拡張子付き)」をそのままキーにしても一致しないことがほとんどです。もし本当にComponentResourceManagerで取りたいなら、対象がフォームresxに入っていること、正しいキー名であることが必要になります。

ただし、フォームアイコンをコードで扱うだけなら、この方法にこだわるメリットは小さく、Properties.Resourcesに寄せた方が簡単で保守も効きます。

パターン2:new Icon(typeof(TLS_FormMain), "TLS_Icon_Green.ico") は「埋め込みリソース」を探しに行く

Icon programIcon = new Icon(typeof(TLS_FormMain), "TLS_Icon_Green.ico");
this.Icon = programIcon;

new Icon(Type, string)は、プロジェクトリソース(Properties/Resources.resx)ではなく、アセンブリの「埋め込みリソース(Manifest Resource)」から読み込む用途で使われます。

そのため、.icoを「Embedded Resource」として埋め込んでいない場合は見つかりません。逆に、埋め込みにするならするで、実際には名前空間を含む完全なリソース名が必要になることが多く、運用でブレやすいです。

埋め込みリソースとして読みたい場合の典型は次のような形です。

using System.Reflection;

var asm = Assembly.GetExecutingAssembly();
using Stream? s = asm.GetManifestResourceStream("YourNamespace.Resources.TLS_Icon_Green.ico");

if (s == null)
{
    throw new InvalidOperationException("埋め込みリソースが見つかりません。名前空間とファイル名を確認してください。");
}

this.Icon = new Icon(s);

ただし、WinFormsのフォームアイコンを設定したいだけなら、ここまでやる必要は基本的にありません。繰り返しになりますが、最短で確実なのはProperties.Resourcesです。

アイコン設定で混同しやすいポイント(WinForms)

「フォームのアイコンを変えたのに変わらない」「一部だけ変わる」などの相談は、アイコンの表示場所が複数あることが原因になりがちです。以下の表で、どれを変えたいのかを整理しておくと解決が早くなります。

見える場所設定に関係する主な要素コードで変更できる?補足
フォームの左上(タイトルバー)Form.Icon / Form.ShowIcon可能ShowIcon=falseだと表示されない
タスクバー上のウィンドウアイコンForm.Icon可能複数フォームがある場合、どのフォームがアクティブかで見え方が変わる
Alt+Tabのサムネイル付近Form.Icon可能OSやテーマで表示位置が異なる
Explorerで見えるexeファイルのアイコンプロジェクトの「アプリケーションアイコン」基本的に不可ビルド時に決まる。実行中に差し替えてもexeの見た目は変わらない

フォームの表示アイコンを変えたい場合は、基本的にForm.Iconを正しく設定すればOKです。一方で、「exeファイルのアイコンまで動的に変えたい」という期待が混ざっていると、どうやっても意図どおりになりません(ビルド成果物のファイルアイコンは別物です)。

よくあるトラブルと解決策

ここからは、実際に現場で発生しやすい“詰まりどころ”を、症状→原因→対処でまとめます。

症状よくある原因対処
this.Icon = Properties.Resources.XXX;で型が合わないリソースがIconではなくbyte[]として生成されているリソースの追加方法を見直す(WinFormsなら「アイコン」として登録)。難しい場合はbyte[]→Iconに変換して渡す
実行してもアイコンが変わらないInitializeComponent()より前で設定している/別の場所で上書きしているコンストラクタでInitializeComponent()の後に設定。もしくはOnLoadなどで最終的に上書きする
タイトルバーの左上に出ないShowIconがfalsethis.ShowIcon = true;を確認
高DPI環境でぼやける/小さすぎる.icoに十分なサイズが入っていない(16/32しかない等)16/32/48/256など複数サイズを含む.icoを用意
一部フォームだけ意図と違うアイコンになる複数フォームで異なるタイミングで設定している共通メソッド化して統一。起動時にアプリ全体のルールを決める

確認ポイント:リソースがIcon型で生成されているか

WinFormsで最短コースを狙うなら、Properties.Resourcesから取得する値がSystem.Drawing.Iconになっている必要があります。目安としては、次のようにそのまま代入できればOKです。

this.Icon = Properties.Resources.TLS_Icon_Green; // ここが通ればIcon型

もしここで型エラーになる場合は、「リソースがアイコンとして登録されていない」ことが多いです。いったんリソースを削除して、プロジェクトのリソース画面から改めて追加し直すと解決しやすいです。

WPFでbyte[]になってしまう場合の考え方

ここからは補足です。WinFormsではなくWPFで同じことをしようとすると、そもそもアイコンの型が異なります。

  • WinForms:Form.Icon は System.Drawing.Icon
  • WPF:Window.Icon は System.Windows.Media.ImageSource

そのため、同じ「リソースに入れた.ico」でも、参照した結果がbyte[]だったり、ImageSourceが必要だったりして混乱が起きます。エラー例としては次のようなものです。

CS0029: 型 ‘byte[]’ を ‘System.Windows.Media.ImageSource’ に暗黙的に変換できません

WPFのおすすめ:pack URI から BitmapFrame を作って Window.Icon に入れる

WPFでは、ファイルを「Resource」としてプロジェクトに含めたうえで、pack URIで参照するのが分かりやすいです。コード設定例は次のとおりです。

using System;
using System.Windows;
using System.Windows.Media.Imaging;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // 例:プロジェクト内の Resources/TLS_Icon_Green.ico を Resource として含めた場合
        var uri = new Uri("pack://application:,,,/Resources/TLS_Icon_Green.ico", UriKind.Absolute);
        this.Icon = BitmapFrame.Create(uri);
    }
}

この方法は「WPFの世界観(ImageSource)」に寄せたやり方なので、WinFormsのIconを無理やり持ち込むより素直に動くことが多いです。

WPFで byte[] しか取れないとき:Iconのデコーダを使ってImageSourceへ

「事情があってProperties.Resourcesからbyte[]として取りたい」「すでにバイナリで管理されている」など、byte[]から出発せざるを得ないケースもあります。その場合は、WPFのIconBitmapDecoderでフレームを取り出すのが扱いやすいです。

using System.IO;
using System.Linq;
using System.Windows.Media;
using System.Windows.Media.Imaging;

public static class WpfIconHelper
{
    public static ImageSource ByteArrayToImageSource(byte[] icoBytes)
    {
        using var ms = new MemoryStream(icoBytes);

        // .ico は複数サイズを持てるので decoder.Frames から用途に合うフレームを選べる
        var decoder = new IconBitmapDecoder(
            ms,
            BitmapCreateOptions.PreservePixelFormat,
            BitmapCacheOption.OnLoad);

        return decoder.Frames.First();
    }
}

使う側はこうなります。

byte[] iconBytes = Properties.Resources.TLS_Icon_Green; // byte[]として生成されているケース
this.Icon = WpfIconHelper.ByteArrayToImageSource(iconBytes);

「byte[]→BitmapImage」という変換はPNG/JPEGでは定番ですが、.icoは複数サイズ・複数フレームを持てるため、WPFではIconBitmapDecoderを使う方が実態に合っています。

補足:byte[]→BitmapImageの一般的な変換(画像全般)

アイコン以外の画像(PNGなど)を扱う場面では、byte[]→BitmapImageのユーティリティもよく使います。参考として、一般画像向けの変換例も置いておきます。

using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;

public static class ByteImageConverter
{
    public static ImageSource ByteToImage(byte[] imageData)
    {
        var biImg = new BitmapImage();
        using var ms = new MemoryStream(imageData);

        biImg.BeginInit();
        biImg.CacheOption = BitmapCacheOption.OnLoad;
        biImg.StreamSource = ms;
        biImg.EndInit();
        biImg.Freeze(); // UIスレッド以外でも使いやすくする

        return biImg;
    }
}

ただし、繰り返しになりますが「WPFのウィンドウアイコン」に限っては、可能ならpack URI+BitmapFrameがシンプルでおすすめです。

実務で役立つチェックリスト

最後に、C#でリソース内アイコンをコードから設定するときに、最低限ここだけ押さえておくと失敗しにくいチェックリストをまとめます。

チェック項目WinFormsWPF
設定したいプロパティの型を理解しているかSystem.Drawing.IconSystem.Windows.Media.ImageSource
.icoをどのリソースに入れたか基本はProperties/Resources.resxResource(pack URI)に寄せると楽
参照する名前は「ファイル名」ではなく「リソース名」重要重要
設定のタイミングInitializeComponent()の後InitializeComponent()の後
高DPI対応の.icoを用意しているか推奨推奨

まとめ

  • WinFormsでフォームアイコンをリソースから設定する最短ルートは、this.Icon = Properties.Resources.リソース名;
  • ComponentResourceManagerはフォームresx向けで、キー名(例:$this.Icon)が一致しないと取れない
  • new Icon(typeof(...), "...")は埋め込みリソース向けで、プロジェクトリソースとは別物
  • WPFはWindow.IconがImageSourceなので、pack URI+BitmapFrameか、byte[]ならIconBitmapDecoderで変換する

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次