tag:crieit.net,2005:https://crieit.net/tags/ListView/feed 「ListView」の記事 - Crieit Crieitでタグ「ListView」に投稿された最近の記事 2019-08-22T09:25:53+09:00 https://crieit.net/tags/ListView/feed tag:crieit.net,2005:PublicArticle/15342 2019-08-22T09:25:53+09:00 2019-08-22T09:25:53+09:00 https://crieit.net/posts/C-ListView 【C#】ListViewのソート処理、ヘッダーのマーク変更をやってみた <p>今回はリストビューのヘッダークリックでソートし、且つマークを表示してみます。<br /> ファイルの一覧なので、ファイル名とサイズのソートをちょっと変えています。</p> <p>プログラムは、下記の記事のものを流用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2018/02/15/post-3938/" target="_blank" rel="noopener" data-blogcard="1">【C#】非同期でファイルとフォルダのサイズを表示する</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="新規クラスの作成"><a href="#%E6%96%B0%E8%A6%8F%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">新規クラスの作成</a></h3> <p>ListViewItemSorter.cs</p> <pre><code>using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Windows.Forms; namespace WindowsFormsApp1 { public class ListViewItemSorter : IComparer { /// <summary> /// 比較する方法 /// </summary> public enum ComparerMode { /// <summary> /// 文字列として比較 /// </summary> String, /// <summary> /// 数値(Int32型)として比較 /// </summary> Integer, /// <summary> /// 日時(DataTime型)として比較 /// </summary> DateTime, /// <summary> /// ファイル名として比較 /// </summary> FileName, /// <summary> /// ファイルサイズとして比較 /// </summary> FileSize }; private ComparerMode[] _columnModes; private int _column; /// <summary> /// 並び替えるListView列の番号 /// </summary> public int Column { set { //現在と同じ列の時は、昇順降順を切り替える if (_column == value) { if (Order == SortOrder.Ascending) { Order = SortOrder.Descending; } else if (Order == SortOrder.Descending) { Order = SortOrder.Ascending; } } _column = value; } get { return _column; } } /// <summary> /// 昇順か降順か /// </summary> public SortOrder Order { set; get; } /// <summary> /// 並び替えの方法 /// </summary> public ComparerMode Mode { set; get; } /// <summary> /// 列ごとの並び替えの方法 /// </summary> public ComparerMode[] ColumnModes { set { _columnModes = value; } } /// <summary> /// コンストラクタ /// </summary> /// <param name="col">並び替える列の番号</param> /// <param name="ord">昇順か降順か</param> /// <param name="cmod">並び替えの方法</param> public ListViewItemSorter(int col, SortOrder ord, ComparerMode cmod) { Column = col; Order = ord; Mode = cmod; } public ListViewItemSorter() { Column = 0; Order = SortOrder.Ascending; Mode = ComparerMode.String; } //xがyより小さいときはマイナスの数、大きいときはプラスの数、 //同じときは0を返す public int Compare(object x, object y) { if (Order == SortOrder.None) { //並び替えない時 return 0; } int result = 0; //ListViewItemの取得 ListViewItem itemx = (ListViewItem)x; ListViewItem itemy = (ListViewItem)y; //並べ替えの方法を決定 if (_columnModes != null &amp;&amp; _columnModes.Length > Column) { Mode = _columnModes[Column]; } //並び替えの方法別に、xとyを比較する switch (Mode) { case ComparerMode.String: //文字列をとして比較 result = string.Compare(itemx.SubItems[Column].Text, itemy.SubItems[Column].Text); break; case ComparerMode.Integer: //Int32に変換して比較 //.NET Framework 2.0からは、TryParseメソッドを使うこともできる result = int.Parse(itemx.SubItems[Column].Text).CompareTo( int.Parse(itemy.SubItems[Column].Text)); break; case ComparerMode.DateTime: //DateTimeに変換して比較 //.NET Framework 2.0からは、TryParseメソッドを使うこともできる result = DateTime.Compare( DateTime.Parse(itemx.SubItems[Column].Text), DateTime.Parse(itemy.SubItems[Column].Text)); break; case ComparerMode.FileName: result = CompareFileName(itemx.Name, itemy.Name); break; case ComparerMode.FileSize: result = CompareFileSize(itemx.SubItems[Column].Text, itemy.SubItems[Column].Text); break; } //降順の時は結果を+-逆にする if (Order == SortOrder.Descending) { result = -result; } //結果を返す return result; } /// <summary> /// ファイル名の比較をします. /// </summary> /// <param name="path1"></param> /// <param name="path2"></param> /// <returns></returns> private int CompareFileName(string path1, string path2) { FileInfo fi1 = new FileInfo(path1); FileInfo fi2 = new FileInfo(path2); if (fi1.Attributes == FileAttributes.Directory &amp;&amp; fi2.Attributes != FileAttributes.Directory) { return -1; } else if (fi1.Attributes != FileAttributes.Directory &amp;&amp; fi2.Attributes == FileAttributes.Directory) { return 1; } return string.Compare(path1, path2); } /// <summary> /// 単位付きのファイルサイズを比較します. /// </summary> /// <param name="size1"></param> /// <param name="size2"></param> /// <returns></returns> private int CompareFileSize(string sizeWithUnit1, string sizeWithUnit2) { string size1 = "0"; string unit1 = ""; string size2 = "0"; string unit2 = ""; List<string> units = new List<string>() { "KB","MB","GB"}; if (!string.IsNullOrEmpty(sizeWithUnit1)) { size1 = sizeWithUnit1.Split(null)[0]; unit1 = sizeWithUnit1.Split(null)[1]; } if (!string.IsNullOrEmpty(sizeWithUnit2)) { size2 = sizeWithUnit2.Split(null)[0]; unit2 = sizeWithUnit2.Split(null)[1]; } // 単位が違う場合は単位で比較 if (unit1 != unit2) { return units.IndexOf(unit1).CompareTo(units.IndexOf(unit2)); } return decimal.Parse(size1).CompareTo(decimal.Parse(size2)); } } } </code></pre> <h3 id="グローバル変数、構造体、定数の追加"><a href="#%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E5%A4%89%E6%95%B0%E3%80%81%E6%A7%8B%E9%80%A0%E4%BD%93%E3%80%81%E5%AE%9A%E6%95%B0%E3%81%AE%E8%BF%BD%E5%8A%A0">グローバル変数、構造体、定数の追加</a></h3> <p>下記を追加します。</p> <p>Form1.cs</p> <pre><code> private ListViewItemSorter ltvFileListSorter = null; [StructLayout(LayoutKind.Sequential)] public struct HDITEM { public Int32 mask; public Int32 cxy; [MarshalAs(UnmanagedType.LPTStr)] public String pszText; public IntPtr hbm; public Int32 cchTextMax; public Int32 fmt; public Int32 lParam; public Int32 iImage; public Int32 iOrder; }; // Parameters for ListView-Headers private const Int32 HDI_FORMAT = 0x0004; private const Int32 HDF_LEFT = 0x0000; private const Int32 HDF_STRING = 0x4000; private const Int32 HDF_SORTUP = 0x0400; private const Int32 HDF_SORTDOWN = 0x0200; private const Int32 LVM_GETHEADER = 0x1000 + 31; // LVM_FIRST + 31 private const Int32 HDM_GETITEM = 0x1200 + 11; // HDM_FIRST + 11 private const Int32 HDM_SETITEM = 0x1200 + 12; // HDM_FIRST + 12 /// <summary> /// リストビューヘッダのイメージ登録 /// </summary> /// <param name="Handle"></param> /// <param name="msg"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> [DllImport("user32.dll", EntryPoint = "SendMessage")] private static extern IntPtr SendMessageITEM(IntPtr Handle, Int32 msg, IntPtr wParam, ref HDITEM lParam); </code></pre> <h3 id="初期化処理の修正"><a href="#%E5%88%9D%E6%9C%9F%E5%8C%96%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">初期化処理の修正</a></h3> <p>初期化時にソートクラスを設定</p> <p>Form1.cs</p> <pre><code> // ソートクラスの設定 ltvFileListSorter = new ListViewItemSorter(0, SortOrder.Ascending, ListViewItemSorter.ComparerMode.String); ltvFileListSorter.ColumnModes = new ListViewItemSorter.ComparerMode[] { ListViewItemSorter.ComparerMode.FileName, ListViewItemSorter.ComparerMode.String, ListViewItemSorter.ComparerMode.String, ListViewItemSorter.ComparerMode.FileSize }; listView1.ListViewItemSorter = ltvFileListSorter; // ソートマークの設定 SetSortMark(listView1.Handle, 0, ltvFileListSorter.Order); </code></pre> <h3 id="新規メソッド追加"><a href="#%E6%96%B0%E8%A6%8F%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E8%BF%BD%E5%8A%A0">新規メソッド追加</a></h3> <p>リストのヘッダがクリックされた際のイベントを追加</p> <p>Form1.cs</p> <pre><code> /// <summary> /// ファイル一覧列クリックイベントハンドラ /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) { ltvFileListSorter.Column = e.Column; listView1.Sort(); // 初期化 foreach (ColumnHeader c in listView1.Columns) { SetSortMark(listView1.Handle, c.Index, SortOrder.None); } SetSortMark(listView1.Handle, e.Column, ltvFileListSorter.Order); } </code></pre> <h3 id="リストヘッダーのマークを設定する処理を追加"><a href="#%E3%83%AA%E3%82%B9%E3%83%88%E3%83%98%E3%83%83%E3%83%80%E3%83%BC%E3%81%AE%E3%83%9E%E3%83%BC%E3%82%AF%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E5%87%A6%E7%90%86%E3%82%92%E8%BF%BD%E5%8A%A0">リストヘッダーのマークを設定する処理を追加</a></h3> <pre><code> /// <summary> /// リストビューのヘッダーソートマークの制御. /// </summary> /// <param name="listViewHandle"></param> /// <param name="colIdx"></param> /// <param name="order"></param> public static void SetSortMark(IntPtr listViewHandle, int colIdx, SortOrder order) { IntPtr hColHeader = SendMessage(listViewHandle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero); HDITEM hdItem = new HDITEM(); IntPtr colHeader = new IntPtr(colIdx); hdItem.mask = HDI_FORMAT; IntPtr rtn = SendMessageITEM(hColHeader, HDM_GETITEM, colHeader, ref hdItem); if (order == SortOrder.Ascending) { hdItem.fmt &amp;= ~HDF_SORTDOWN; hdItem.fmt |= HDF_SORTUP; } else if (order == SortOrder.Descending) { hdItem.fmt &amp;= ~HDF_SORTUP; hdItem.fmt |= HDF_SORTDOWN; } else if (order == SortOrder.None) { hdItem.fmt &amp;= ~HDF_SORTDOWN &amp; ~HDF_SORTUP; } rtn = SendMessageITEM(hColHeader, HDM_SETITEM, colHeader, ref hdItem); } </code></pre> <p> </p> <h3 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h3> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/CSharpListSort001.jpg" alt="ファイル名でソート" /></p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/CSharpListSort002.jpg" alt="サイズでソート" /></p> <p>無事にソート、マークの表示ができました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>何故、標準で出来ないのか。</p> <p>謎は深まりますね。</p> <p>次回は今のところ未定です。<br /> ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15337 2019-08-20T14:41:12+09:00 2019-08-20T14:41:12+09:00 https://crieit.net/posts/C 【C#】非同期でファイルとフォルダのサイズを表示する <p>今回は検索なんかをやる予定でしたが、ちょっと寄り道して<br /> 選択されたファイル、フォルダの総数とデータ容量を非同期で画面に表示してみました。</p> <p>プログラムは前回のものを流用します。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2018/02/14/post-3933/" target="_blank" rel="noopener" data-blogcard="1">【C#】TreeView と ListView でエクスプローラーみたいな操作をする</a></p> <h2 id="画面の修正"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BF%AE%E6%AD%A3">画面の修正</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/CSharpFileSize001.jpg" alt="ラベルの追加" /></p> <p>リストビューの下にラベルを設置します。</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="ファイルサイズ取得用の非同期メソッドを追加"><a href="#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B5%E3%82%A4%E3%82%BA%E5%8F%96%E5%BE%97%E7%94%A8%E3%81%AE%E9%9D%9E%E5%90%8C%E6%9C%9F%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E8%BF%BD%E5%8A%A0">ファイルサイズ取得用の非同期メソッドを追加</a></h3> <pre><code> // 非同期処理のキャンセル用変数 private CancellationTokenSource tokenSource = null; /// <summary> /// ファイル数とファイルサイズを設定します. /// </summary> private void SetFileCountAndSize() { // ファイル数、サイズの設定 try { // 非同期処理中だった場合はキャンセル if (tokenSource != null) { tokenSource.Cancel(); } using (tokenSource = new CancellationTokenSource()) { SetFileCountAndSizeAsync(tokenSource.Token); } } catch (ObjectDisposedException oe) { Console.WriteLine("非同期処理が中止されました。"); } catch (OperationCanceledException ex) { MessageBox.Show("ファイル情報の取得に失敗しました。", "エラー"); return; } finally { tokenSource = null; } } /// <summary> /// ファイル数とファイルサイズを設定します(非同期処理). /// </summary> private async void SetFileCountAndSizeAsync(CancellationToken token) { long fileSize = 0; int fileCount = 0; lbl_fileCountValue.Text = ""; lbl_fileSizeValue.Text = ""; foreach (ListViewItem item in listViewTo.Items) { token.ThrowIfCancellationRequested(); // ディレクトリだった場合 FileInfo fi = new FileInfo(item.Name); if (fi.Attributes == FileAttributes.Directory) { string[] pathList = Directory.GetDirectories(item.Name, "*", SearchOption.AllDirectories); foreach (string path in pathList) { List<long> data = await GetFileCountAndSizeTask(path, fileSize, fileCount); lbl_fileSizeValue.Text = getFileSize(data[0]); lbl_fileCountValue.Text = data[1].ToString(); fileSize = data[0]; fileCount = (int)data[1]; } } else { fileSize += fi.Length; fileCount++; lbl_fileSizeValue.Text = getFileSize(fileSize); lbl_fileCountValue.Text = fileCount.ToString(); } } } /// <summary> /// ファイル数とファイルサイズを取得します. /// </summary> /// <param name="filePath"></param> /// <param name="fileSize"></param> /// <param name="fileCount"></param> /// <returns></returns> private async Task<List<long>> GetFileCountAndSizeTask(String filePath, long fileSize, int fileCount) { List<long> result = new List<long>(); await Task.Run(() => { DirectoryInfo dirInfo = new DirectoryInfo(filePath); // フォルダ内の全ファイルの合計サイズを計算する foreach (FileInfo fi in dirInfo.GetFiles()) { fileSize += fi.Length; fileCount++; } result.Add(fileSize); result.Add(fileCount); }); return result; } </code></pre> <h3 id="既存イベント処理の修正"><a href="#%E6%97%A2%E5%AD%98%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">既存イベント処理の修正</a></h3> <p>ファイルの追加、削除時にファイルサイズを設定する。</p> <pre><code> /// <summary> /// 追加ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_add_Click(object sender, EventArgs e) { var selectedItems = listView1.SelectedItems; foreach (ListViewItem item in selectedItems) { // 項目をコピーして名前を再設定 ListViewItem copy = (ListViewItem)item.Clone(); copy.Name = item.Name; // 既にリストに含まれていないパスであれば追加 if (listViewTo.Items.Find(copy.Name, false).Length == 0) { listViewTo.Items.Add(copy); } } // ファイル数、サイズの設定 SetFileCountAndSize(); // 列幅を自動調整 listViewTo.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); } /// <summary> /// 削除ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_del_Click(object sender, EventArgs e) { var selectedItems = listViewTo.SelectedItems; foreach (ListViewItem item in selectedItems) { listViewTo.Items.Remove(item); } // ファイル数、サイズの設定 SetFileCountAndSize(); // 列幅を自動調整 listViewTo.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); } </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/02/CSharpFileSize002.jpg" alt="ファイル数、サイズの表示" /></p> <p>スクリーンショットだと分からないですが、ファイル数、データ容量の大きいフォルダなんかを選択した場合に、非同期で表示が更新されます。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>最初は非同期でない方法で試したのですが、<br /> 大きいファイルなんかだと画面が固まってしまうので非同期にしました。</p> <p>やっぱり画面まわりも色々やれることがあって楽しいですね。</p> <p>次回はボタンに画像を表示してみたいと思います。</p> doraxdora tag:crieit.net,2005:PublicArticle/15335 2019-08-19T10:29:42+09:00 2019-08-19T10:30:06+09:00 https://crieit.net/posts/C-TreeView-ListView-5d59fb865f1f4 【C#】TreeView と ListView でエクスプローラーみたいな操作をする <p>エクスプローラ風画面作成の続きです。<br /> 今回は、リストビューに表示されたディレクトリをダブルクリックで下層に移動し、<br /> 「上へ」ボタンで上層に移動するサンプルとなります。</p> <p>プログラムは前回のものを流用します。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2018/02/08/post-3866/" target="_blank" rel="noopener" data-blogcard="1">【C#】7zip(Sfx)で自己解凍exeを作成する</a></p> <h2 id="画面の修正"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BF%AE%E6%AD%A3">画面の修正</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/CSharpExplore000.jpg" alt="画面の修正" /></p> <p>1つ上のディレクトリに移動するためのボタンを追加します。</p> <h2 id="プログラム修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E4%BF%AE%E6%AD%A3">プログラム修正</a></h2> <h3 id="ツリービューの指定した項目を選択状態にする処理を追加"><a href="#%E3%83%84%E3%83%AA%E3%83%BC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AE%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E9%A0%85%E7%9B%AE%E3%82%92%E9%81%B8%E6%8A%9E%E7%8A%B6%E6%85%8B%E3%81%AB%E3%81%99%E3%82%8B%E5%87%A6%E7%90%86%E3%82%92%E8%BF%BD%E5%8A%A0">ツリービューの指定した項目を選択状態にする処理を追加</a></h3> <pre><code> /// <summary> /// ツリービューの指定されたディレクトリパスの項目を選択状態にします. /// </summary> /// <param name="dirPath"></param> private void selectTreeViewItem(TreeView trv, string dirPath) { // ツリービューのノードを走査 foreach (TreeNode node in trv.Nodes) { // 再帰処理で対象のディレクトリを処理 selectTreeViewItem(node, dirPath); } } /// <summary> /// ツリービューの指定されたディレクトリパスの項目を選択状態にします(再帰処理用). /// </summary> /// <param name="node"></param> /// <param name="dirPath"></param> private void selectTreeViewItem(TreeNode node, string dirPath) { foreach (TreeNode n in node.Nodes) { FileInfo fi = new FileInfo(n.FullPath); // リストビューで表示されたディレクトリ名と一致する場合 if (dirPath == fi.FullName) { // 選択状態にする treeView1.Focus(); treeView1.SelectedNode = n; break; } selectTreeViewItem(n, dirPath); } } </code></pre> <h3 id="ファイル一覧ダブルクリック時のイベントを追加"><a href="#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E4%B8%80%E8%A6%A7%E3%83%80%E3%83%96%E3%83%AB%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E6%99%82%E3%81%AE%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%82%92%E8%BF%BD%E5%8A%A0">ファイル一覧ダブルクリック時のイベントを追加</a></h3> <pre><code> /// <summary> /// リストビューダブルクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listView1_MouseDoubleClick(object sender, MouseEventArgs e) { // 選択されたファイル情報を取得 ListViewItem selectedListItem = listView1.SelectedItems[0]; FileInfo fi = new FileInfo(selectedListItem.Name); // ディレクトリであればファイル一覧の内容を更新する if (fi.Attributes == FileAttributes.Directory) { // ツリービュー上で対象のディレクトリ(ノード)が // 表示されている場合は選択状態にする selectTreeViewItem(treeView1, fi.FullName); // ファイル一覧の内容を更新 setListItem(fi.FullName); selectedItem = fi.FullName; } } </code></pre> <h3 id="追加した「上へ」ボタンの処理を追加"><a href="#%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%9F%E3%80%8C%E4%B8%8A%E3%81%B8%E3%80%8D%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E8%BF%BD%E5%8A%A0">追加した「上へ」ボタンの処理を追加</a></h3> <pre><code> /// <summary> /// 上へボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnUp_Click(object sender, EventArgs e) { DirectoryInfo di = new DirectoryInfo(selectedItem); if (di.Parent != null) { selectedItem = di.Parent.FullName; setListItem(di.Parent.FullName); // 表示されている場合は選択状態にする selectTreeViewItem(treeView1, selectedItem); } } </code></pre> <p> </p> <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/02/CSharpExplore001.jpg" alt="修正後画面" /></p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/CSharpExplore002.jpg" alt="上へボタンクリック" /></p> <p>無事に操作できるようになりました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ひとまずエクスプローラーみたいな感じになってきました。</p> <p>あとは検索とかもやってみるかもしれません。(予定)</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15293 2019-08-01T11:01:21+09:00 2019-08-01T11:01:21+09:00 https://crieit.net/posts/C-ListView-ListView 【C#】ListViewの項目を別のListViewへ追加する <p>今回は ListViewに表示したフォルダ、ファイルを別の ListView に移す(コピー)してみたいと思います。</p> <p>プログラムは前回のものを流用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2018/01/31/post-3807/" target="_blank" rel="noopener" data-blogcard="1">【C#】TreeViewとListViewにシステムイメージ(アイコン)を表示する</a></p> <h2 id="画面修正"><a href="#%E7%94%BB%E9%9D%A2%E4%BF%AE%E6%AD%A3">画面修正</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/ListViewItemCopy000.jpg" alt="画面の修正" /></p> <p>「追加」、「削除」、「追加項目をクリア」ボタンと、別のListViewを追加します。<br /> ボタンにはそれぞれ「Click」イベントを追加。</p> <h2 id="プログラム修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E4%BF%AE%E6%AD%A3">プログラム修正</a></h2> <h3 id="既存処理の修正"><a href="#%E6%97%A2%E5%AD%98%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">既存処理の修正</a></h3> <p>起動時の処理時に、追加した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); // ListViewFrom SendMessage(listView1.Handle, LVM_SETIMAGELIST, new IntPtr(LVSIL_SMALL), imageListHandle); // ListViewTo SendMessage(listViewTo.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()); // リストビューのヘッダーを設定 listViewTo.View = View.Details; listViewTo.Clear(); listViewTo.Columns.Add("名前"); listViewTo.Columns.Add("種類"); listViewTo.Columns.Add("更新日時"); listViewTo.Columns.Add("サイズ"); } </code></pre> <p>また、追加する項目が既に別のListViewに存在するかどうかチェックするため<br /> ファイル・フォルダのフルパスをListViewItemに持たせるように修正します。<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.Name = di.FullName; 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.Name = info.FullName; 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="イベント処理の追加"><a href="#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%87%A6%E7%90%86%E3%81%AE%E8%BF%BD%E5%8A%A0">イベント処理の追加</a></h3> <p>各ボタンのクリックイベントを追加</p> <pre><code> /// <summary> /// 追加ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_add_Click(object sender, EventArgs e) { var selectedItems = listView1.SelectedItems; foreach (ListViewItem item in selectedItems) { // 項目をコピーして名前を再設定 ListViewItem copy = (ListViewItem)item.Clone(); copy.Name = item.Name; // 既にリストに含まれていないパスであれば追加 if (listViewTo.Items.Find(copy.Name, false).Length == 0) { listViewTo.Items.Add(copy); } } // 列幅を自動調整 listViewTo.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); } /// <summary> /// 削除ボタンクリックイベント. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_del_Click(object sender, EventArgs e) { var selectedItems = listViewTo.SelectedItems; foreach (ListViewItem item in selectedItems) { listViewTo.Items.Remove(item); } // 列幅を自動調整 listViewTo.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); } /// <summary> /// 追加項目をクリアボタンクリックイベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnClear_Click(object sender, EventArgs e) { listViewTo.Items.Clear(); } </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/02/ListViewItemCopy001.jpg" alt="項目を選択" /></p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2018/02/ListViewItemCopy002.jpg" alt="追加ボタンを押下" /></p> <p>選択した項目を別の ListView に追加することができました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>複数のフォルダやファイルに対して何か処理をする際に、ユーザに選ばせるようなイメージですね。<br /> まあよくある感じですか。</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