6月 17

zipファイルを解凍・展開する

C#でzipファイルを解凍する方法は幾つかあるようですが
以下の条件で絞って探してみました。

・Framework2.0以降で利用できること
・とにかく簡単なこと
・J#などに依存しないこと

2011年7月の現時点ではオープンソースで開発されている
DotNetZip ライブラリを利用するのがお手軽そうです。

まずは DotNetZip のサイトより
必要なランタイムDLLをダウンロードしてください。

DotNetZipトップページはこちら

トップページを開いたら Downloads タブを選択します。
ファイルが何種類か並んでいますが
とりあえず必要なのはランタイムのみなので

DotNetZipLib-Runtime-v1.9.zip

のようにランタイムが圧縮されたファイルをダウンロードし
適当なフォルダに解凍してください。
(バージョン番号やファイル名は今後変更されると思います)

展開すると以下のような階層で色々入っていますが
開発に必要なのは※印の付いた
DotNetZip-v1.9 フォルダの Ionic.Zip.dll ファイルです。

    │  Contents.txt
    │  License.txt
    │  PleaseDonate.txt
    │  Readme.txt
    │
    ├─DotNetZip-Reduced-v1.9
    │      Ionic.Zip.Reduced.dll
    │      Readme.txt
    │
    ├─DotNetZip-v1.9
    │      Ionic.Zip.dll ※これを使います
    │      Readme.txt
    │
    ├─DotNetZip-v1.9-CompactFramework
    │      Ionic.Zip.CF.dll
    │      Readme.txt
    │
    ├─zlib-v1.9
    │      Ionic.Zlib.dll
    │      Readme.txt
    │
    └─Zlib-v1.9-CompactFramework
            Ionic.Zlib.CF.dll
            Readme.txt

次に、Ionic.Zip.dll ファイルを
プロジェクトの参照設定に追加してください。

やり方は幾つかありますが
1.ソリューションエクスプローラーの参照設定を右クリックして参照の追加
2.参照の追加Dialogが開いたら参照タブより上記ファイルを選択

あとは下記サンプルコードを参考にしてください。
数行のコードで解凍が可能です。

もちろん、アプリを実行する際は
Ionic.Zip.dll ランタイムも必要になるのでお忘れなく。
ライセンスも最新情報を確認しましょう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ionic.Zip;    // usingを忘れずに
using Ionic.Zlib;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // zipファイル読み込み
            ZipFile zip = new ZipFile(@"c:\sample.zip", Encoding.GetEncoding("shift_jis"));

            // 展開する。すでにあれば上書きする。
            zip.ExtractAll(@"c:\", ExtractExistingFileAction.OverwriteSilently);

            // 後始末。面倒ならusingしておいてもおk
            zip.Dispose();
        }
    }
}
6月 17

ブラウザーを作る

ブラウザーを作る、と書くと大袈裟かもしれませんが
WebBrowserコントロールをFormに貼り付けるだけで
簡単なブラウザーを作ることができます。

下記の例は
開きたいアドレスをurlプロパティーに設定しています。

webbrowser

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Yahoo!を開く
            Uri yahoo = new Uri("http://www.yahoo.co.jp/");
            webBrowser1.Url = yahoo;
        }
    }
}
6月 17

タイマーの使い方(定期的な処理を行う)

定期的な処理を行うにはTimerコントロールを使います。
TimerコントロールをFormにドラッグ&ドロップすると
デザイン画面の下のほうにtimer1が現れます。

主なプロパティーは2つ。
Enabledでタイマーが有効か無効かを設定します。(初期値はFalseで無効)
Intervalでタイマーイベントが発生する周期をミリ秒単位で指定します。

後はタイマーイベントが発生すると呼び出される
Tickイベントハンドラを追加し、(イベント一覧でTickの欄をダブルクリックで自動生成)
定期的に行いたい処理をTickイベントハンドラ内に記述します。

下記例では1秒毎に秒数をカウントし、
VisualStudioの出力画面に経過病数を表示します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        // 秒数
        private int sec = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 1秒単位でイベントを発生させる
            timer1.Interval = 1000;

            // タイマーを有効に
            timer1.Enabled = true;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            sec++;
            Console.WriteLine(sec.ToString() + "秒経過...");
        }
    }
}
6月 17

ノードを右クリックでも選択する

TreeViewのNodeを右クリックでも選択できるようにする例です。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TreeViewSample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // マウスクリックされた時のハンドラ追加
            treeView1.NodeMouseClick += new TreeNodeMouseClickEventHandler(treeView1_NodeMouseClick);
        }

        void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            // 選択しているNodeを指定
            treeView1.SelectedNode = e.Node;
        }
    }
}
6月 17

ノードを自動でSort(並べ替え)する

TreeViewのNodeを自動で文字列順に並び替え(Sort)するには
Sortedプロパティーにtrueを指定します。
フォルダTreeなどを作る場合に有効です。

なお、Sortedプロパティは
プロパティウィンドウにも入力サジェストにも表示されませんが
コーディングするとちゃんとコンパイルできます。

自前でSort用関数を用意してもOKですが
お手軽なので利用しましょう。

なお、Nodeが既に追加されている状態で当該プロパティをtrueに設定すると
そのタイミングでSortされるので
BeginUpdate~で囲むほうが高速です。

元々trueなのをtrueとしても効果は発揮されないので
再Sortしたい場合は、一旦falseしてtrueするとよいです。

    treeView1.BeginUpdate();
    treeView1.Sorted = true;
    treeView1.EndUpdate();
6月 17

ノードの背景色を設定する

NodeのBackColorプロパティーに色を指定します。

treeview_backcolor

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // わかりやすいように幅全体を選択状態にします(任意)
            treeView1.FullRowSelect = true;
            treeView1.ShowLines = false;

            // 適当に10個のNodeを登録し、それぞれの背景色を設定
            for (int i = 0; i < 10; i++)
            {
                TreeNode node = treeView1.Nodes.Add(i.ToString());
                node.BackColor = Color.Pink;
            }
        }
    }
}
6月 17

ノードの幅全体を強調表示する

TreeViewのノード選択時に、ノード全体を幅いっぱいに強調表示する場合は
FullRowSelect プロパティーにtrueを設定します。
このとき、ShowLines プロパティーを合わせてfalseにしなければ効果が無いので注意です。

treeview_fullrow

    treeView1.ShowLines = false;        // これがtrueだとFullRowSelectのtrueが効かない
    treeView1.FullRowSelect = true;     // ノードの幅全体を強調表示する
6月 17

エクスプローラーのようなドライブとフォルダのツリーを作る

TreeViewコントロールを使って
エクスプローラーのようなドライブとフォルダのツリーを作る例です。

treeview_folder

すべてのNodeを起動時に列挙、追加するとかなり処理が重くなってしまうため
必要なNodeのみ追加し、下位Nodeは+ボックスをクリックされる都度検索、追加しています。

■InitTree関数
	ここで起動時に論理ドライブの一覧を取得し、TreeViewに登録しています。
	ノードが展開可能であることを表す+ボックスを表示させるために
	文字列dummyをダミーで追加しています。
	
■BeforeExpandイベントハンドラ
	+ボックスがクリックされ、Nodeが展開される前に呼び出されます。
	この中でフォルダ内のサブフォルダ一覧を取得し、追加しています。

なお、これは必須ではないのですが
ドライブの種類に応じたアイコンや
フォルダの選択時、非選択時のアイコンを表示するために
次のようなImageListを準備し、TreeViewのImageListプロパティーに設定しています。

treeview_imagelist

また、ドライブの種別を取得するために
参照設定にSystem.Managementを追加しています。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Management;    // 参照設定に追加を忘れずに
using System.IO;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            treeView1.BeforeExpand += new TreeViewCancelEventHandler(treeView1_BeforeExpand);
            treeView1.Dock = DockStyle.Fill;
            treeView1.ImageList = this.imageList1;
            treeView1.Sorted = true;	// ※文字列順に自動Sortします。

            InitTree();
        }

        private void InitTree()
        {
            ManagementObject mo = new ManagementObject();

            // 論理ドライブ一覧を列挙
            string[] drives = Environment.GetLogicalDrives();
            foreach (string drive in drives)
            {
                // ドライブのタイプを取得
                mo.Path = new ManagementPath("Win32_LogicalDisk='" + drive.TrimEnd('\\') + "'");
                int drivetype = Convert.ToInt32(mo.Properties["DriveType"].Value);

                // ドライブのタイプごとにアイコンを設定
                TreeNode node = new TreeNode();
                switch (drivetype)
                {
                    case 0:
                        //ドライブを判別できません
                        continue;
                        break;
                    case 1:
                        //ドライブ上にルートディレクトリが存在しません
                        continue;
                        break;
                    case 2:
                        //Floppy
                        node = new TreeNode(drive, 4, 4);
                        break;
                    case 3:
                    case 6:
                        //HardDisk
                        node = new TreeNode(drive, 0, 0);
                        break;
                    case 4:
                        //Network
                        node = new TreeNode(drive, 5, 5);
                        break;
                    case 5:
                        //CD-ROM
                        node = new TreeNode(drive, 3, 3);
                        break;
                }

                treeView1.Nodes.Add(node);

                // +ボックスを表示するためのダミー
                node.Nodes.Add("dummy");
            }
        }


        void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            TreeNode node = e.Node;

            // 展開するノードのフルパスを取得
            string fullpath = node.FullPath;
            node.Nodes.Clear();

            // フォルダ一覧を取得
            DirectoryInfo dirs = new DirectoryInfo(fullpath);
            try
            {
                foreach (DirectoryInfo dir in dirs.GetDirectories())
                {
                    // フォルダを追加
                    TreeNode nodeFolder = new TreeNode(dir.Name, 1, 2);
                    node.Nodes.Add(nodeFolder);

                    // +ボックスを表示するためのダミー
                    nodeFolder.Nodes.Add("dummy");
                }
            }
            catch { }
        }
    }
}