tag:crieit.net,2005:https://crieit.net/tags/WindowsForms/feed
「WindowsForms」の記事 - Crieit
Crieitでタグ「WindowsForms」に投稿された最近の記事
2019-08-28T09:29:46+09:00
https://crieit.net/tags/WindowsForms/feed
tag:crieit.net,2005:PublicArticle/15359
2019-08-28T09:29:46+09:00
2019-08-28T09:29:46+09:00
https://crieit.net/posts/C-WindowsForm
【C#】WindowsForm にチェックボックスを動的に配置してみる
<p>あるデータを元にチェックボックスを等間隔に動的配置する方法を試してみました。</p>
<h2 id="プロジェクト新規作成"><a href="#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%96%B0%E8%A6%8F%E4%BD%9C%E6%88%90">プロジェクト新規作成</a></h2>
<p>今回は新規でプロジェクトを作成します。</p>
<p>Visual Studio を起動して、「ファイル」>「新規」からプロジェクトを作成してください。</p>
<h2 id="画面の作成"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BD%9C%E6%88%90">画面の作成</a></h2>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/08/CSharpDynaCheck000.jpg" alt="画面作成中" /></p>
<p>「Label」、「TableLayoutPanel」、「Button」を配置します。<br />
TableLayoutPanelによって、均等にチェックボックスを並べていくようになります。</p>
<h2 id="プログラム"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0">プログラム</a></h2>
<h3 id="クラス追加"><a href="#%E3%82%AF%E3%83%A9%E3%82%B9%E8%BF%BD%E5%8A%A0">クラス追加</a></h3>
<p>チェックボックスのデータを保持するクラスの追加</p>
<p>Option.cs</p>
<pre><code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SampleCheckBoxDynamicArrangement
{
/// <summary>
/// 選択肢クラス
/// </summary>
class Option
{
/// <summary>
/// チェックされているかどうか
/// </summary>
public Boolean IsChecked { set; get; }
/// <summary>
/// 表示テキスト
/// </summary>
public String Text { set; get; }
/// <summary>
/// 値
/// </summary>
public String Value { set; get; }
}
}
</code></pre>
<p> </p>
<h3 id="メインの処理"><a href="#%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E5%87%A6%E7%90%86">メインの処理</a></h3>
<p>Form1.cs</p>
<pre><code>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 SampleCheckBoxDynamicArrangement
{
public partial class Form1 : Form
{
private int toggleFlg = 0;
/// <summary>
/// 選択肢リスト
/// </summary>
private List<Option> options =new List<Option> {
new Option{ IsChecked = false, Text = "チェック1", Value = "0"},
new Option{ IsChecked = false, Text = "チェック2", Value = "1"},
new Option{ IsChecked = false, Text = "チェック3", Value = "2"},
new Option{ IsChecked = false, Text = "チェック4", Value = "3"},
new Option{ IsChecked = false, Text = "チェック5", Value = "4"},
new Option{ IsChecked = false, Text = "チェック6", Value = "5"},
new Option{ IsChecked = false, Text = "チェック7", Value = "6"},
new Option{ IsChecked = false, Text = "チェック8", Value = "7"},
new Option{ IsChecked = false, Text = "チェック9", Value = "8"},
new Option{ IsChecked = false, Text = "チェック10", Value = "9"}
};
/// <summary>
/// 初期表示時の処理
/// </summary>
public Form1()
{
InitializeComponent();
AddCheckboxHorizontally();
}
/// <summary>
/// チェックボックスを横方向に配置していく
/// </summary>
private void AddCheckboxHorizontally()
{
foreach (Option o in options)
{
CheckBox cb = createCheckBox(o);
// 特に指定しなければ横に追加していく
tableLayoutPanel1.Controls.Add(cb);
}
}
/// <summary>
/// チェックボックスを縦方向に配置していく
/// </summary>
private void AddCheckboxVertically() {
int col = 0;
int row = 0;
int maxRow = 4;
for(int idx = 0; idx < options.Count; idx++)
{
CheckBox cb = createCheckBox(options[idx]);
if (row == maxRow)
{
row = 0;
col++;
}
// 特に指定しなければ横に追加していく
tableLayoutPanel1.Controls.Add(cb, col, row++);
}
}
/// <summary>
/// チェックボックスを作成.
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
private CheckBox createCheckBox(Option o)
{
CheckBox cb = new CheckBox();
cb.Checked = o.IsChecked;
cb.Text = o.Text;
cb.Name = "chk_" + o.Value;
cb.CheckedChanged += new EventHandler(CheckBoxCheckedChangeHandler);
return cb;
}
/// <summary>
/// チェックボックス状態変更ハンドラー.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CheckBoxCheckedChangeHandler(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
int index = int.Parse(cb.Name.Replace("chk_", ""));
options[index].IsChecked = cb.Checked;
}
/// <summary>
/// チェックボックスを削除する
/// </summary>
private void RemoveCheckBox()
{
for (int idx = tableLayoutPanel1.Controls.Count - 1; idx >= 0; idx--)
{
Control c = tableLayoutPanel1.Controls[idx];
tableLayoutPanel1.Controls.Remove(c);
}
}
/// <summary>
/// 切替ボタンクリックイベント.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
RemoveCheckBox();
if (toggleFlg == 0)
{
AddCheckboxVertically();
toggleFlg = 1;
} else
{
AddCheckboxHorizontally();
toggleFlg = 0;
}
}
/// <summary>
/// 登録ボタンクリックイベント.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
int count = 0;
foreach (Option o in options)
{
if (o.IsChecked)
{
sb.Append(Environment.NewLine).Append(o.Text);
count++;
}
}
sb.Insert(0, "チェックされたのは次の" + count + "件です。");
if (count > 0)
{
MessageBox.Show(this, sb.ToString(), "チェック");
}
else
{
MessageBox.Show(this, "チェックされていません。", "チェック");
}
}
}
}
</code></pre>
<h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/08/CSharpDynaCheck001.jpg" alt="起動直後" /></p>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/08/CSharpDynaCheck002.jpg" alt="切替ボタン押下" /></p>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/08/CSharpDynaCheck003.jpg" alt="いくつかチェックする" /></p>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/08/CSharpDynaCheck004.jpg" alt="登録ボタン押下" /></p>
<p>縦、横に順番で並べることができました。</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>動的に配置できれば、<br />
選択肢に増減がある場合などに使えますね。</p>
<p>もっと上手い方法もあるかと思いますが、<br />
今回はサクッと、選択肢のリストをグローバルで保持し、<br />
チェックボックスのIDを利用してどこのチェックボックスがチェックされているかを判定しました。</p>
<p>ソース(プロジェクト)は、<br />
初めて GitHub にアップしてみましたが、上げ方合ってるのかな。。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://github.com/doraxdora/SampleCheckBoxDynamicArrangement">GitHub</a></p>
<p>何かの参考になれば。</p>
<p>ではでは。</p>
<p> </p>
doraxdora
tag:crieit.net,2005:PublicArticle/15290
2019-07-31T09:51:53+09:00
2019-07-31T09:51:53+09:00
https://crieit.net/posts/C-TreeView-ListView-5d40e6294240e
【C#】TreeViewとListViewにシステムイメージ(アイコン)を表示する
<p>前回に引き続き、Windows Forms で、エクスプローラーのような表示をするために、<br />
今回はファイル・フォルダの横にアイコンを表示してみます。</p>
<p>プログラムは前回のものを流用します。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2018/01/30/post-3801/">https://www.doraxdora.com/blog/2018/01/30/post-3801/</a></p>
<h2 id="プログラムの修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%BF%AE%E6%AD%A3">プログラムの修正</a></h2>
<h3 id="DLL関数の呼び出し宣言を追加"><a href="#DLL%E9%96%A2%E6%95%B0%E3%81%AE%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E5%AE%A3%E8%A8%80%E3%82%92%E8%BF%BD%E5%8A%A0">DLL関数の呼び出し宣言を追加</a></h3>
<p>システムイメージを利用するには「Shll32.dll」、「user32.dll」の関数を呼び出す必要があるため、関数呼び出しの宣言を追加します。</p>
<pre><code> // DllImportに必要
using System.Runtime.InteropServices;
/// <summary>
/// ファイル情報を取得
/// </summary>
/// <param name="pszPath"></param>
/// <param name="dwFileAttributes"></param>
/// <param name="psfi"></param>
/// <param name="cbFileInfo"></param>
/// <param name="uFlags"></param>
/// <returns></returns>
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
/// <summary>
/// イメージリストを登録
/// </summary>
/// <param name="hWnd"></param>
/// <param name="Msg"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
</code></pre>
<h3 id="構造体や定数の定義"><a href="#%E6%A7%8B%E9%80%A0%E4%BD%93%E3%82%84%E5%AE%9A%E6%95%B0%E3%81%AE%E5%AE%9A%E7%BE%A9">構造体や定数の定義</a></h3>
<p>DLL関数で利用する構造体や定数の定義を追加します。</p>
<pre><code> /// <summary>
/// SHGetFileInfo関数で使用する構造体
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
// ファイル情報用
private const int SHGFI_LARGEICON = 0x00000000;
private const int SHGFI_SMALLICON = 0x00000001;
private const int SHGFI_USEFILEATTRIBUTES = 0x00000010;
private const int SHGFI_OVERLAYINDEX = 0x00000040;
private const int SHGFI_ICON = 0x00000100;
private const int SHGFI_SYSICONINDEX = 0x00004000;
private const int SHGFI_TYPENAME = 0x000000400;
// TreeView用
private const int TVSIL_NORMAL = 0x0000;
private const int TVSIL_STATE = 0x0002;
private const int TVM_SETIMAGELIST = 0x1109;
// ListView用
private const int LVSIL_NORMAL = 0;
private const int LVSIL_SMALL = 1;
private const int LVM_SETIMAGELIST = 0x1003;
// 選択された項目を保持
private String selectedItem = "";
</code></pre>
<h3 id="起動時にシステムイメージを登録"><a href="#%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E7%99%BB%E9%8C%B2">起動時にシステムイメージを登録</a></h3>
<p>起動時の処理で、TreeView、ListViewにイメージのリストを登録します。</p>
<pre><code> /// <summary>
/// 起動時の処理
/// </summary>
public Form1()
{
InitializeComponent();
// イメージリストの設定
SHFILEINFO shFileInfo = new SHFILEINFO();
IntPtr imageListHandle = SHGetFileInfo(String.Empty, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
// TreeView
SendMessage(treeView1.Handle, TVM_SETIMAGELIST, new IntPtr(TVSIL_NORMAL), imageListHandle);
// ListView
SendMessage(listView1.Handle, LVM_SETIMAGELIST, new IntPtr(LVSIL_SMALL), imageListHandle);
// ドライブ一覧を走査してツリーに追加
foreach (String drive in Environment.GetLogicalDrives())
{
// アイコンの取得
int iconIndex = 0;
IntPtr hSuccess = SHGetFileInfo(drive, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_SYSICONINDEX );
if (hSuccess != IntPtr.Zero)
{
iconIndex = shFileInfo.iIcon;
}
// 新規ノード作成
// プラスボタンを表示するため空のノードを追加しておく
TreeNode node = new TreeNode(drive, iconIndex, iconIndex);
node.Nodes.Add(new TreeNode());
treeView1.Nodes.Add(node);
}
// 初期選択ドライブの内容を表示
setListItem(Environment.GetLogicalDrives().First());
}
</code></pre>
<h3 id="ListViewの内容更新時の処理を修正"><a href="#ListView%E3%81%AE%E5%86%85%E5%AE%B9%E6%9B%B4%E6%96%B0%E6%99%82%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E4%BF%AE%E6%AD%A3">ListViewの内容更新時の処理を修正</a></h3>
<p>TreeViewが選択された際にListViewの内容を更新する処理で、<br />
表示するファイル、フォルダ―のイメージを取得して設定します。</p>
<pre><code> /// <summary>
/// リストビューの項目を設定します.
/// </summary>
private void setListItem(String filePath)
{
// リストビューのヘッダーを設定
listView1.View = View.Details;
listView1.Clear();
listView1.Columns.Add("名前");
listView1.Columns.Add("種類");
listView1.Columns.Add("更新日時");
listView1.Columns.Add("サイズ");
try
{
// フォルダ一覧
DirectoryInfo dirList = new DirectoryInfo(filePath);
foreach (DirectoryInfo di in dirList.GetDirectories())
{
ListViewItem item = new ListViewItem(di.Name);
// フォルダ種類、アイコンの取得
String type = "";
int iconIndex = 0;
SHFILEINFO shFileInfo = new SHFILEINFO();
IntPtr hSuccess = SHGetFileInfo(di.FullName, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (hSuccess != IntPtr.Zero)
{
type = shFileInfo.szTypeName;
iconIndex = shFileInfo.iIcon;
}
// 各列の内容を設定
item.ImageIndex = iconIndex;
item.SubItems.Add(type);
item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", di.LastAccessTime));
item.SubItems.Add("");
// リストに追加
listView1.Items.Add(item);
}
// ファイル一覧
List<String> files = Directory.GetFiles(filePath).ToList<String>();
foreach (String file in files)
{
FileInfo info = new FileInfo(file);
ListViewItem item = new ListViewItem(info.Name);
// ファイル種類、アイコンの取得
String type = "";
int iconIndex = 0;
SHFILEINFO shinfo = new SHFILEINFO();
IntPtr hSuccess = SHGetFileInfo(info.FullName, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (hSuccess != IntPtr.Zero)
{
type = shinfo.szTypeName;
iconIndex = shinfo.iIcon;
}
// 各列の内容を設定
item.ImageIndex = iconIndex;
item.SubItems.Add(type);
item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", info.LastAccessTime));
item.SubItems.Add(getFileSize(info.Length));
listView1.Items.Add(item);
}
}
catch (IOException ie)
{
MessageBox.Show(ie.Message, "選択エラー");
}
// 列幅を自動調整
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
</code></pre>
<h3 id="TreeView展開時の処理を修正"><a href="#TreeView%E5%B1%95%E9%96%8B%E6%99%82%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E4%BF%AE%E6%AD%A3">TreeView展開時の処理を修正</a></h3>
<p>同様に TreeView を展開する際の処理で、<br />
フォルダ―のアイコンを取得して設定するように修正します。</p>
<pre><code> /// <summary>
/// ツリービュー項目展開時(前)のイベントハンドラ.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
TreeNode node = e.Node;
node.Nodes.Clear();
try
{
DirectoryInfo dirList = new DirectoryInfo(node.FullPath);
foreach (DirectoryInfo di in dirList.GetDirectories())
{
// フォルダのアイコンを取得
SHFILEINFO shinfo = new SHFILEINFO();
int iconIndex = 0;
IntPtr hSuccess = SHGetFileInfo(di.FullName, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (hSuccess != IntPtr.Zero)
{
iconIndex = shinfo.iIcon;
}
// 子を追加してノードを展開
TreeNode child = new TreeNode(di.Name, shinfo.iIcon, shinfo.iIcon);
child.ImageIndex = iconIndex;
child.Nodes.Add(new TreeNode());
node.Nodes.Add(child);
}
}
catch (IOException ie)
{
MessageBox.Show(ie.Message, "選択エラー");
}
}
</code></pre>
<h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/01/TreeViewIcon001.jpg" alt="起動イメージ" /></p>
<p>無事に TreeView、ListViewにアイコンを表示することができ、<br />
更にエクスプローラーのようなUIになりました。</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>プログラムについては共通化したり、別クラスに処理をまとめたりできるので整理が必要ですが、<br />
ひとまずアイコンを表示する方法を試してみました。</p>
doraxdora
tag:crieit.net,2005:PublicArticle/15276
2019-07-26T09:51:39+09:00
2019-07-26T09:51:39+09:00
https://crieit.net/posts/C-TreeView-ListView
【C#】TreeView と ListView でエクスプローラーのような表示をする
<p>おはようございます。</p>
<p>今回はC#のWindowsFormで、<br />
エクスプローラーのようなUIを実装したいと思います。</p>
<p>WindowsFormはまだブログに書いていないので、新規でプロジェクトを作成してください。</p>
<h2 id="画面の作成"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BD%9C%E6%88%90">画面の作成</a></h2>
<p><img src="https://www.doraxdora.com/wp-content/uploads/2018/01/CSharpTreeView000.jpg" alt="コントロールの配置" /></p>
<p>左側にフォルダのTreeView、右側に選択されたツリー項目に格納されているフォルダ・ファイル一覧を表示するための ListView を配置します。</p>
<h2 id="プログラムの実装"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E5%AE%9F%E8%A3%85">プログラムの実装</a></h2>
<h3 id="ファイルサイズ変換処理"><a href="#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B5%E3%82%A4%E3%82%BA%E5%A4%89%E6%8F%9B%E5%87%A6%E7%90%86">ファイルサイズ変換処理</a></h3>
<div>
ファイルサイズ(バイト)を単位付きに変換するメソッド
```
/// <summary>
/// ファイルサイズを単位付きに変換して返します.
/// </summary>
/// <param name="fileSize"></param>
/// <returns></returns>
private String getFileSize(long fileSize)
{
String ret = fileSize + " バイト";
if (fileSize > (1024f * 1024f * 1024f))
{
ret = Math.Round((fileSize / 1024f / 1024f / 1024f), 2).ToString() + " GB";
}
else if (fileSize > (1024f * 1024f))
{
ret = Math.Round((fileSize / 1024f / 1024f), 2).ToString() + " MB";
}
else if (fileSize > 1024f)
{
ret = Math.Round((fileSize / 1024f)).ToString() + " KB";
}
return ret;
}
```
### リストビュー項目設定処理
TreeView が選択された際に、格納されている項目の内容を ListView に設定するメソッド
```
/// <summary>
/// リストビューの項目を設定します.
/// </summary>
private void setListItem(String filePath)
{
// リストビューのヘッダーを設定
listView1.View = View.Details;
listView1.Clear();
listView1.Columns.Add("名前");
listView1.Columns.Add("更新日時");
listView1.Columns.Add("サイズ");
try
{
// フォルダ一覧
DirectoryInfo dirList = new DirectoryInfo(filePath);
foreach (DirectoryInfo di in dirList.GetDirectories())
{
ListViewItem item = new ListViewItem(di.Name);
item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", di.LastAccessTime));
item.SubItems.Add("");
listView1.Items.Add(item);
}
// ファイル一覧
List<String> files = Directory.GetFiles(filePath).ToList<String>();
foreach (String file in files)
{
FileInfo info = new FileInfo(file);
ListViewItem item = new ListViewItem(info.Name);
item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", info.LastAccessTime));
item.SubItems.Add(getFileSize(info.Length));
listView1.Items.Add(item);
}
}
catch (IOException ie)
{
MessageBox.Show(ie.Message, "選択エラー");
}
// 列幅を自動調整
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
```
### 起動時の処理
画面表示時に TreeView と、デフォルトで選択されるフォルダ(ドライブ)の内容を ListViewに設定します。
```
/// <summary>
/// 起動時の処理
/// </summary>
public Form1()
{
InitializeComponent();
// ドライブ一覧を走査してツリーに追加
foreach (String drive in Environment.GetLogicalDrives())
{
// 新規ノード作成
// プラスボタンを表示するため空のノードを追加しておく
TreeNode node = new TreeNode(drive);
node.Nodes.Add(new TreeNode());
treeView1.Nodes.Add(node);
}
// 初期選択ドライブの内容を表示
setListItem(Environment.GetLogicalDrives().First());
}
```
### TreeView展開時の処理
展開された項目の子ノードを追加する処理を実装
```
/// <summary>
/// ツリービュー項目展開時(前)のイベントハンドラ.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
TreeNode node = e.Node;
String path = node.FullPath;
node.Nodes.Clear();
try
{
DirectoryInfo dirList = new DirectoryInfo(path);
foreach (DirectoryInfo di in dirList.GetDirectories())
{
TreeNode child = new TreeNode(di.Name);
child.Nodes.Add(new TreeNode());
node.Nodes.Add(child);
}
}
catch (IOException ie)
{
MessageBox.Show(ie.Message, "選択エラー");
}
}
```
### TreeView項目選択時の処理
選択された項目に格納されているファイル・フォルダ一覧を表示
```
/// <summary>
/// ツリービュー項目選択時(前)のイベントハンドラ.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
setListItem(e.Node.FullPath);
}
```
## 起動してみる
![起動後の画面](https://www.doraxdora.com/wp-content/uploads/2018/01/CSharpTreeView001.jpg)
左側、TreeViewにドライブ、フォルダの一覧、右側に選択されたフォルダの内容を表示することができました。
## まとめ
エクスプローラーのようなコントローラーであれば標準であっても良さそうなもんですけどね。
とりあえずしばらくは WindowsForm をやっていく予定です。
ではでは。
</div>
doraxdora