みなさんこんにちは!ヒロポンです!
毎日張り切ってプログラミングの勉強してますか!!!!!
私は張り切ってやっています!!!!
さて今回はC#使いなら一度は使ったことがあるクラスOpenFileDialogについて書いていきたいと思います!
OpenFileDialogは継承できない!
💡 OpenFileDialog をフィールドで持つ場合のパターンは別記事 OpenFileDialog をフォームのフィールドにする方法 で書いてます。
このOpenFileDialogって初期設定が結構めんどくさい!!!
だから継承してCustomOpenFileDoalog的なものを作りたいがOpenFileDialogは継承が許されてません!

こんな感じでコンパイルエラーが出るので、コードの中身を見てみるとsealedクラスとして定義されています。

となるとどうあがいても継承はできません。
そこで、思ったのがOpenFileDialogをフィールドに持ったCustomOpenFileDialogを作ればよいのでは?ということ
実際にCustomOpenFileDialogを作ってみる。
とりあえずこんな感じで作ってみた。
using System;
using System.IO;
using System.Windows.Forms;
namespace CustomOpenFileDialog
{
public class CustomOpenFileDialog
{
private OpenFileDialog _ofd;
public string FileName => _ofd.FileName;
public CustomOpenFileDialog()
{
_ofd = new OpenFileDialog();
_ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
_ofd.Title = "ファイル選択";
_ofd.Filter = "htmlファイル(*.html)| *.html";
}
public DialogResult ShowDialog()
{
return _ofd.ShowDialog();
}
}
}
画面はこんな感じで用意して

テキストボックス右側のボタンを押したらダイアログが立ち上がる仕組み
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CustomOpenFileDialog
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var cofd = new CustomOpenFileDialog();
if (cofd.ShowDialog() == DialogResult.OK)
{
textBox1.Text = cofd.FileName;
}
}
}
}
これを実行すると下記のような感じになる。

初期画面ではちゃんとデスクトップが表示されていて、ダイアログのタイトルにもちゃんと値が入っている。
それにちゃんとフィルターもかかっている。
ファイルを選択すると下記のような感じになる。

ちゃんとファイルが選択されている。
これを応用すると下記のような感じにもできる。
まずはFilterTypeのEnumを作る
public enum FilterType
{
HTML = 1,
CSV
}
でCustomOpenFileDialogのコンストラクタの引数にセットする。
public class CustomOpenFileDialog
{
private OpenFileDialog _ofd;
public string FileName => _ofd.FileName;
public CustomOpenFileDialog(FilterType type)
{
_ofd = new OpenFileDialog();
_ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
_ofd.Title = "ファイル選択";
switch (type)
{
case FilterType.CSV:
_ofd.Filter = "csvファイル(*.csv)| *.csv";
break;
case FilterType.HTML:
_ofd.Filter = "htmlファイル(*.html)| *.html";
break;
}
}
public DialogResult ShowDialog()
{
return _ofd.ShowDialog();
}
}
使う側はこんな感じ
private void button1_Click(object sender, EventArgs e)
{
var cofd = new CustomOpenFileDialog(FilterType.CSV);
if (cofd.ShowDialog() == DialogResult.OK)
{
textBox1.Text = cofd.FileName;
}
}
これで実行すると下記のような感じでFilterがちゃんと変わってる

継承ができなくても別の方法があるはず!
今回OpenFileDialogの継承ができないために別の方法で継承的なことをしたけども、結構こんなパターンが多いんですよね!!
でもいろいろ調べてみたら方法はありますし、なんなら方法を考えるのが楽しい!ってのがあります。
そもそもその方法を考えるのがエンジニアの仕事であって醍醐味であると思います!
とにかくこういうパターンは経験でしかないので、公私問わず勉強をして経験を積むしかないのでしょうね!!
今回のコードはGithubに上げています!
実際の動きを見たい場合はかきリポジトリにアクセスしてみてください!
https://github.com/adaman3568/blog-source-demo
💡 補足: OpenFileDialog でハマる3点
俺もこの OpenFileDialog、 業務でハマってきたところを3つ並べておきます。
① 継承不可なので Wrapper 必須
sealed class 指定で継承不可。 拡張したい場合は「Wrapper クラス + 集約 (has-a 関係)」で対応。 業務系では FileDialogHelper 等のユーティリティクラスを作る。
② Filter プロパティの構文ミス
Filter = "CSV files|*.csv|All files|*.*" のパイプ区切りを間違えると例外。 「表示名 | 拡張子 | 表示名 | 拡張子」の繰り返し。 セミコロン使うと複数拡張子 ( "画像|*.png;*.jpg" )。
③ ShowDialog() の戻り値判定
if (dialog.ShowDialog() == DialogResult.OK) が定石。 戻り値見ずに dialog.FileName 使うと、 ユーザーがキャンセルした時に空文字で NRE。
❓ よくある質問
Q1. SaveFileDialog との違いは?
A. OpenFileDialog = 既存ファイル選択、 SaveFileDialog = 新規ファイル名指定 + 上書き確認。 API は似てるが用途が違う。
Q2. 複数選択するには?
A. Multiselect = true 設定 → FileNames プロパティで配列取得。 デフォルトは単一選択。
Q3. 初期ディレクトリ指定は?
A. InitialDirectory プロパティ。 業務系では「最後に選択したフォルダ」を Settings に保存 → 次回オープン時に復元。
Q4. ファイル拡張子フィルタの動的設定は?
A. FilterIndex プロパティで起動時のデフォルトフィルタを指定 (1-based)。 ユーザーが選択変更すると自動更新。
Q5. ダイアログ閉じ忘れの心配は?
A. using (var dlg = new OpenFileDialog()) で自動 Dispose。 OpenFileDialog は IDisposable なので using 推奨。
📚 関連記事





執筆者
バイブス父さん — 業務 SE 7 年 (正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SES 複数社・フリーランスエージェント複数経由の経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。
🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る




