C# 入門講座
Visual Studio 2005 Visual Studio 2008 Visual Studio 2010 Visual Studio 2012 Visual Studio 2013 Visual Studio 2015 Visual Studio 2017 Visual Studio 2019

第11回 卒業制作

この記事が対象とする製品・バージョン (バージョンの確認方法)

VS2019 Visual Studio 2019 対象です。
VS2017 Visual Studio 2017 対象です。
VS2015 Visual Studio 2015 対象です。
VS2013 Visual Studio 2013 対象です。
VS2012 Visual Studio 2012 対象ですが一部画面が異なる場合があります。
VS2010 Visual Studio 2010 対象ですが一部画面が異なる場合があります。
VS2008 Visual Studio 2008 対象ですが一部画面が異なる場合があります。
VS2005 Visual Studio 2005 対象ですが一部画面が異なる場合があります。
VS.NET 2003 Visual Studio 2003 対象外ですがほとんどの操作は同じなので参考になります。
VS.NET 2002 Visual Studio (2002) 対象外ですがほとんどの操作は同じなので参考になります。

概要

・いろいろなファイルを見ることができるアプリケーションを作る

・ファイルの一覧を保存・読み込みできるようにする

 

1.目標

 

入門講座の技術的な解説は前回で終了です。今回は実際に使えるアプリケーションを作っていく過程を紹介します。手順は1ステップごとに書いていきますので、是非、実際にC#を操作してアプリケーション作りを体感してください。

これから作るアプリケーションのプログラムではいままで解説しなかった知識やキーワードが登場します。そのため、多くの人はよく理解しないまま手順どおりに作っていくだけの作業になるでしょう。

しかし、今回の私の意図は、「細かい部分がよくわからなくても、とにかく実際のアプリケーションを作る手順を体感する」というものです。ですから、よくわからなくても順を 追ってアプリケーションを完成させることができた人は今回の目標を達成できたということになります。

私が目指しているのは、新しい発見や、知らなかった操作方法、まだ知らないテクニックにふれることの刺激を感じ取っていただくことです。

このような作業の経験は必ず身になります。

 

2.完成品

 

これから作るアプリケーションは次のようなものです。

■画像1:完成品が動作しているところ。画像は私が食べたBecker'sのハンバーガーです。

主な機能

・画像・テキスト・Excel・Word・Html. pdfなどさまざまな種類のファイルを見ることができる。

・左側のファイル一覧をクリックすると、そのファイルの内容が右側に表示される。

・ファイル一覧にファイルを追加するには、ファイルをドラッグ&ドロップする。

・ファイル一覧に登録されている内容を保存することができる。保存した内容はあとで呼び出すことができる。

※Excel, WordのファイルはExcel, Wordがインストールされている環境でのみ正常に表示できます。その他のファイルも環境により表示できる場合とできない場合があります。入門講座の練習用プログラムなのでうまく読み込めないファイルがあっても割り切ってください。

3.作成

 

それでは、いよいよ実際にプログラムを始めていきます。完成までの大まかな手順は次のようになります。

1.土台を作る。

フォームにコントロールを配置する。この時点では見かけだけ完成する。実際の機能はほとんどない。

2.左側のファイル一覧の機能をプログラムする。

この段階では、ファイル一覧にファイルを追加できるようになる。

3.ファイルを表示できるようにする。

4.ファイル一覧の保存・呼び出し機能をつける。

5.細部と整える。

  

3-1.土台を作る。

 

3-1-1.新しいプロジェクトの作成。

新しいプロジェクトを作成してください。この手順は説明するまでもないでしょう。

今までどおり、Windows フォームアプリケーション (.NET Framework)を選択してください。

プロジェクト名は「MultiFileViewer」にしてください。

フレームワークは .NET Framework 4.7.2 にしてください。(4.8でもよいですが、ヒントが英語で表示されるので少しだけやりにくいです。)

プロジェクトを作成したら一度保存しておくことをお勧めします。

 

3-1-2.フォームにコントロールを配置。

次の手順に従ってフォームにコントロールを配置して、プロパティを設定してください。

 

▼手順1

SplitContainerコントロール(読み方:SplitContainer = スプリットコンテナ)をフォームに配置します。このSplitContainerコントロールの名前はSplitContainer1となります。

ツールボックス上ではSplitContainerは「コンテナ」というグループのところにありますので見つからない場合は、「コンテナ」グループをヒントにするとよいでしょう。下の画像も参考にしてください。

ツールボックス上のSplitContainerコントロール

■画像2:ツールボックス上のSplitContainerコントロール

配置すると自動的にフォーム全体に広がって下の画像のような状態になります。

SplitContainerコントロールをフォームに配置したところ

■画像3:SplitContainerコントロールをフォームに配置したところ

 

▼手順2

次に、 上の画像でPanel1と書いてある部分にSplitContainerコントロールをもう1つ配置します。このSplitContainerコントロールの名前はSplitContainer2となります。配置すると自動的にPanel1全体に広がって下の画像のような状態になります。

■画像

SplitContainer2の右上に小さなな三角が現れるのでクリックします。

三角が現れていない場合は、左側のPanel1とPanel2の間の境界線をクリックすると現れます。

SplitContainerのタスクから[上下スプリッターの方向]をクリックして下さい。

2つ目のSplitContainerコントロールの分割方向を変更する

■画像4:2つ目のSplitContainerコントロールの分割方向を変更する

ここまでの作業でフォームは次のような状態になります。

2つ目のSplitContainerコントロールの配置完了

■画像5:2つ目のSplitContainerコントロールの配置完了

 

操作方法 操作 - プロパティウィンドウで設定する方法

プロパティウィンドウを使って同じ設定をすることもできます。プロパティウィンドウを使って設定するにはSplitContainer2を選択して、タスクウィンドウのOrientationプロパティ(読み方:Orientation = オリエンテーション)の値をHorizontal(読み方:Horizontal = ホリゾンタル)にして下さい。

  

▼手順3

ListBoxコントロール(読み方:ListBox = リストボックス)をSplitContainer2Panel2に配置します。名前をlstFileNameにしてください。

■画像6:ツールボックス上のListBoxコントロール

プログラム完成時にはこのListBoxコントロールにファイルの一覧が表示されます。

ListBoxコントロールを配置したところ

■画像7:ListBoxコントロールを配置したところ

配置したらlstFileNameのプロパティを下記のように設定してください。

プロパティ 読み方 設定する値 備考
Dock ドック Fill

プロパティウィンドウではDockプロパティを選択するときに真ん中にある一番大きな四角が Fill です。正しく選択すると文字で Fill と表示されます。

AllowDrop アロゥドロップ True lstFileNameにファイルをドロップできるようになります。
DisplayMember ディスプレイメンバー Name lstFileNameに何を表示するのかの設定です。

 

▼手順4

WebBrowserコントロール(読み方:WebBrowser = ウェブブラウザー)をSplitContainer1Panel2に配置してください。

コントロールパネル上のWebBrowserコントロール

配置すると自動的にいっぱいに広がります。

WebBrowserコントロールを配置したところ

■画像8:WebBrowserコントロールを配置したところ

このWebBrowserコントロールについては何もプロパティを変更しないでおいてください。名前も初期状態のWebBrowser1のままで構いません。

 

3-1-3.確認

この段階で実行してみてください。マウスを使って境界線をドラッグしてフォーム内の区画の大きさが変更できることを確認してください。

左上にPanel1lstFileNameを区切る短い境界線もあるのでこちらも試してみてください。

3-1-4.解説

以上でこの作業は終了です。この作業の意味を簡単に説明します。

フォームに配置したSplitContainerコントロールはフォーム上での配置を自動的に調節してくれるコントロールです。 このコントロールには次の2つの働きがあります。

このようにユーザーが自由にサイズを変更できるようにフォームを設計する場合はSplitContainerコントロールがたいへん役に立ちます。

 

3-2.左側のファイル一覧の機能をプログラムする。

 

3-2-1.この段階の概要

この段階では、左側に配置したlstFileNameにファイルをドラッグ&ドロップできるようにします。ドロップしたファイルの情報ががlstFileNameに追加されていくようにします。

 

3-2-2.ドロップしたファイルのファイル情報を追加する。

lstFileNameDragEnterイベントハンドラーを生成します。

DragEnterイベントハンドラーを生成するには、プロパティウィンドウでイベントを選択して DragEnter をダブルクリックします。

■画像9:DragEnterイベントの生成

→この辺りの詳しい説明は入門講座第4回 イベントを逃すな をご覧下さい。

 

イベントハンドラーには次のコードを記述してください。

private void lstFileName_DragEnter(object sender, DragEventArgs e)
{
    //ドラッグされているものがファイルであるか確認します。
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        //ファイルであればコピー可能であることを宣言します。
        e.Effect = DragDropEffects.Copy;
    }
}

■リスト2:DragEnterイベント

同様にlstFileNameDragDropイベントハンドラーに 次のコードを追加します。

private void lstFileName_DragDrop(object sender, DragEventArgs e)
{
    //ドロップされたファイルのフルパスを取得します。
    string fileName;
    fileName = (e.Data.GetData(DataFormats.FileDrop) as string[])[0];

    //フルパスからファイル情報を生成してlstFileNameに格納します。
    lstFileName.Items.Add(new System.IO.FileInfo(fileName));
}

■リスト3:DragDropイベント

 

3-2-3.確認

ここまでの作業が完了しているか確認するために、プログラムを実行して、lstFileNameめがけてファイルをドラッグ&ドロップしてみてください。ファイルはどのような種類のものでも構いません。たとえば、デスクトップ上の適当なファイルをドロップしてみてください。

ドロップしたファイルのファイル名が次々にlstFileNameに追加されていくようなら正常です。

エラーになる場合は、もう一度コードを見直してください。

エラーにはならないが、正常に動作しない場合はコードを見直すとともにlstFileNameAllowDropプロパティがTrueになっているか確認してください。

 

3-2-4.解説

ここでのプログラムは入門講座のレベルを超えるものでしたが簡単に説明しておきます。

DragEnterイベントは、ドラッグされてきた何かが自分の上に来たときに発生します。この場合はlstFileNameの上に来たときに発生します。今回は、ドラッグされてきたものがファイルであれば、コピーOKの意思表示をするように命令しています。

DragDropイベントは、ドラッグされてきた何かが自分にドロップされたときに発生します。今回は、ファイルがドロップされてくるはずなので、ファイル情報(FileInfo)をlstFileNameに追加するようにしています。

lstFileNameに表示されるのはファイル情報(FileInfo)のうち、ファイル名です。これはlstFileNameのDisplayMemberプロパティにNameを設定している効果です。

たとえば、DisplayMemberプロパティをFullNameにすると、ファイル名だけではなくフルパスが表示されます。

念のために用語について確認しておきますと、「C:\Windows\隅田川.bmp」をドロップした場合、フルパスは「C:\Windows\隅田川.bmp」、ファイル名は「隅田川.bmp」です。

 

3-3.ファイルを表示できるようにする

 

この段階では、ファイル一覧(=lstFileName)でクリックしたファイルが実際に右側のWebBrowser1に表示されるようにします。

本来ファイルを表示する機能をプログラムするのはとても大変です。ファイルの種類ごとに違った処理が必要となるからです。しかし今回はWebBrowserコントロールがすべてを自動的に処理してくれるので この作業はとても簡単になります。

lstFileNameSelectedIndexChangedイベントに次のコードを追加してください。

private void lstFileName_SelectedIndexChanged(object sender, EventArgs e)
{
    System.IO.FileInfo file = lstFileName.SelectedItem as System.IO.FileInfo;
    webBrowser1.Navigate(file.FullName);
    this.Text = Application.ProductName + " - " + file.FullName;
}

■リスト4

これだけで完成です。実行して確かめてみてください。

ファイル一覧(=lstFileName)に画像やhtmlファイルなどをドロップして、ファイル名をクリックするとちゃんとそれが表示されるのが確認できます。

SelectedIndexChangedイベントはlstFileNameの選択されている内容が変更されたときに発生します。今回は、このときにlstFileNameに格納されているファイル情報(FileInfo)を取り出して、そのフルパスを使ってWebBrowser1Navigateメソッドを呼び出します。

NavigateメソッドはそれがなんであれWebBrowserコントロールで自動的に処理してくれる便利なメソッドです。

 

3-4.ファイル一覧の保存・読み込み機能をつける

 

3-4-1.概要

この段階では、ファイル一覧の内容を保存する機能、および保存したファイル一覧を呼び出す機能をプログラムします。また、保存・読み込みを実行するためのボタンを配置します。

これにより、一度作成したファイル一覧を2回目以降は簡単に呼び出せるようになります。

 

3-4-2.ボタンの配置

まずツールバーに見立てて保存ボタンと読み込みボタンを作成します。本当のツールバー機能を実現することも可能なのですが今回はツールバー風にボタンを並べておくだけにします。

次のようにボタンを配置してください。

■画像11:配置後の画面

コントロール 名前 備考
Button(ボタン) btnSave フォームの左上の方に配置してください。
Button(ボタン) btnLoad btnSaveの右横に配置してください。

■表

ボタンの プロパティを下記のように設定してください。

コントロール プロパティ 設定する値
btnSave Text
btnLoad Text

■表2

今回は、簡単に漢字で「保」や「読」などと表示するようにしました。かっこよくするためにはここに画像を表示するなどの工夫が必要でしょう。

博士のワンポイントレッスン うまく配置できない?
V太 V太:博士~。どんなにやってもボタンが並んでくれませんよ~。大きさも変な大きさになっちゃいます…。
博士 博士:うーむ。Visual Studioのフォームデザイナーによる自動配置機能が働いておるのじゃな。フォームデザイナーにはコントロールを配置する際に回りにあるコントロールと自動的に位置調節を行う機能があるのじゃ。
B子 B子:とりあえずなんとかするにはプロパティウィンドウで直接LocationプロパティやSizeプロパティをコントロールの位置や大きさを数値で指定すると良いわ。これなら自動配置機能は働かないわ。
博士 コントロールを選択した状態でキーボードの矢印キーで位置を微調整することもできるぞ。それから、1つ目のボタンを配置したあと右クリックからコピー&貼り付けすれば同じサイズのボタンがもう1個配置されるぞ。Visual Studioの自動は配置機能を無効化することもできる。それには[ツール]メニューの[オプション]画面から、「Windows フォーム デザイナ」を選択して、レイアウト モードを SnapToGridに変更するのじゃ。この変更はデザイナを開きなおさないと有効にならないので注意じゃな。

 

3-4-3.ファイル一覧を保存できるようにする

ファイル一覧を保存できるようにするために、btnSaveClickイベントに次のコードを追加してください。

private void btnSave_Click(object sender, EventArgs e)
{
    //▼保存するファイルの指定
    SaveFileDialog dialog = new SaveFileDialog();
    dialog.DefaultExt = ".txt"; //既定の拡張子を .txt とします。

    //ファイルを保存するダイアログを開き、閉じられるまで待ちます。OKが押されたか確認します。
    if (dialog.ShowDialog() != DialogResult.OK)
    {
        //OK以外で閉じられた場合何もしません。
        return;
    }

    //▼ファイルへの書き込み
    using (var writer = new System.IO.StreamWriter(dialog.FileName))
    {
        //lstFileNameに格納されているファイル情報を1つずつ取り出します
        foreach (System.IO.FileInfo fileInfo in lstFileName.Items)
        {
            //ファイル情報からフルパスに書き込みます。
            writer.WriteLine(fileInfo.FullName);
        }
    } //end of using
} //end of btnSave_Click

■リスト5

この段階で、このコードがうまく動くかテストしてみてください。正常に動作する場合は、ファイル一覧にいくつかのファイルを追加して、「保」ボタンをクリックすると、ファイル名を選択する画面になります。そこで適当なファイル名を入力し、「保存」をクリックすると、そのファイルにファイル一覧のファイルのフルパスが書き込まれます。

■画像13:ファイル選択画面

プログラムで既定の拡張子として.txtを指定しているため、保存時にファイル名欄で拡張子を指定しないと拡張子は .txt になります。

保存したらメモ帳で保存したファイルを開いてlstFileNameに格納したファイルのフルパスが記録されているか確認してみてください。

 

3-4-4.ファイル一覧を読み込めるようにする

今度は、3-4-3で作成したファイルを読み込めるようにします。btnLoadClickイベントに次のコードを追加してください。

private void btnLoad_Click(object sender, EventArgs e)
{
    //▼開くファイルの指定
    OpenFileDialog dialog = new OpenFileDialog();

    //ファイルを開くダイアログを開き、閉じられるまで待ちます。OKが押されたか確認します。
    if (dialog.ShowDialog() != DialogResult.OK)
    {
        //OK以外で閉じられた場合何もしません。
        return;
    }

    //▼ファイルからの読み込み

    //lstFileNameに格納している内容をすべてクリアします。
    lstFileName.Items.Clear();

    //指定されたファイルの内容を1行ずつ処理します。
    foreach(string line in System.IO.File.ReadAllLines(dialog.FileName))
    {
        //フルパスからファイル情報を生成してlstFileNameに格納します。
        lstFileName.Items.Add(new System.IO.FileInfo(line));
    }
} //end of btnLoad_Click

■リスト6

プログラムができたら、実際に実行して確認してみてください。正常に動作する場合は、「読」ボタンをクリックするとファイルを選択する画面が表示され、そこで選択したファイルの内容を読み込んで、ファイル一覧に表示します。

なお、無関係なファイルを選択するとエラーになったら異常な動作をしますので、かならず「保」ボタンで作成したファイルを選択するようにしてください。

本来は無関係なファイルが指定された場合のチェックをプログラムで行う必要があるのですが、今回は割愛します。というのもこのソフトは仮に異常終了した場合でもユーザーにはほとんどダメージがないからです。

 

3-5.細部を整える

 

3-5-1.概要

すでに基本的な機能はすべて完成しています。最後に少し手を加えて仕上げを行います。

このようにプログラムを作るときは、基本的な機能を完成させてから細かい点を仕上げていくというスタイルをお勧めします。はじめから細かいところを作りこんでいくとなかなかプログラムが進まないので退屈ですし、一通り出来上がってから見えてくる部分というものもあります。

ここでは、一番初めのタイトルバーの表示が form1 となっているのが美しくないので直します。また、ファイル一覧にまったくファイルがない状態でも「保」ボタンが押せるのは妙だと思うのでこの場合は「保」ボタンをクリックできないようにします。

他にも目に付く点はあるのですが、それらは簡単に触れるに留め、今回はあまり欲張らないことにしましょう。

 

3-5-2.タイトルバーの表示

タイトルバーの表示に関しては、すでにlstFileNameSelectedIndexChangedイベントで、アプリケーション名とフルパスが表示されるようにプログラムしてあります。

以下の部分がそのコードです。

this.Text = Application.ProductName + " - " + file.FullName;

これはこれでよいと思うのですが、一番初めにプログラムを開始した時点では「form1」となっているのでこのときにアプリケーション名を表示するように改造します。

FormのShownイベントに次のコードを追加してください。

private void Form1_Shown(object sender, EventArgs e)
{
    this.Text = Application.ProductName;
}

■リスト7

 

メモ メモ  -  製品名

Application.ProductName はアプリケーションの製品名を表しています。製品名はデフォルトではプロジェクト名です。つまり、今回は MultiFileViewer です。

プロパティウィンドウを使ってFormのTextプロパティを MultiFileViewer に設定しても初期表示が変わるのでOKなんですが、後で製品名を変更したときに連動してFormのTextプロパティを変更するという手間が発生します。プログラムで必ずApplication.ProductNameを設定するようにしておけばこの手間はありません。製品名を変更することはほとんどないと思いますし、表示だけの話なのであまり重要ではありません。FormのTextプロパティに設定してしまっても良いです。

なお、製品名を変更するには、プロジェクトのプロパティで「アプリケーション」タブの「アセンブリ情報」ボタンをクリックします。

製品名

 

 

 

3-5-3.初めは「保」ボタンをクリックできないようにする

「保」ボタンはファイル一覧が空のときはクリックできないようにしてしまいましょう。

そのために、まずプロパティウィンドウでbtnSaveEnabledプロパティをfalseにしてください。

そして、次の2箇所にコードを追加してください。

1つ目はlstFileNameDragDropイベントハンドラーの一番下です。

private void lstFileName_DragDrop(object sender, DragEventArgs e)
{

    (中略)

    //保ボタンを有効化します。
     btnSave.Enabled = true;
}

■リスト8

2つ目はbtnLoadClickイベントハンドラーの一番下です。

private void btnLoad_Click(object sender, EventArgs e)
{

    (中略)

    //保ボタンを有効化します。
    btnSave.Enabled = true;

} //end of btnLoad_Click

■リスト9

3-5-4.見かけの問題

最後に私が一番気になっているのは見かけです。コントロールをぺたぺた貼っていっただけなので仕方ないのですが、このソフトは見かけが素敵ではありません。

この点の改良は個人のセンスの問題もありますし、技術的な問題もありますが、なんといって「保」ボタンと「読」ボタンがださいです。ここを何とかするにはそれなりに知識が必要となってきますがやはりC#のツールバー機能を利用するとよいでしょう。ツールバーを配置するにはToolStripコントロール(読み方:ToolStrip = トゥールストリップ)を使用しますが始めての方は苦労するでしょう。余力があればチャレンジしてみてください。

4.完成

 

お疲れ様です。以上でプログラムは完成しました。

多分、実際に作っていただいた方にはほとんどコードを書いてあるままに操作するだけ作業になってしまったのではないかと思いますが、それで良いのです。この作業を通して必ず得るものがあったはずです。冒頭にも書いたように新しい発見や、知らなかった操作方法、まだ知らないテクニックにふれることの刺激、そんなものを感じ取っていただければ私の意図は達成できたことになります。

また、コントロールを貼り付けて、それぞれのイベントにプログラムしていくイベントドリブンという手法についても今回の経験を通して理解が深まったのではないでしょうか。

ふりかえって今回作成したアプリケーションについて反省してみます。

まず、WebBworserコントロールの力を使うことにより、さまざまな種類のファイルを簡単に表示することができました。これはたいへん良いことだと思います。

悪い点ではファイル一覧の扱い方です。このファイル一覧は扱いにくいです。たとえば、間違って登録してしまったファイルを削除することができません。また、ファイルの順番を入れ替えることもできません。

もう一つ、このアプリケーションではファイルを見るだけで編集することができません。画像ファイルならそれでも満足できるのですが、テキストファイルの場合は編集したくなります。

さらに、このアプリケーションの可能性を考えて見ましょう。どのような機能を追加することができるでしょうか?

私が考えているのは、スライドショー機能です、一定時間ごとにファイルが自動的に切り替わっていけばそのままスライドショーができますね。

入門レベルでは、これらの反省点を元に具体的なコードの形で改造していくことは困難だと思います。いつかあなたの考えていることをそのままコードにかけるようになる日が来たら、そのときこそあなたの欲しい機能をどんどんプログラムして行こうではありませんか。現段階ではあせらないで一歩ずつ進んで行きましょう。