原文: http://zetcode.com/gui/csharpwinforms/advancedcontrols/

在 Mono Winforms 教程的这一部分中,我们介绍一些更高级的控件。 即ListBoxListViewTreeView控件。

ListBox

ListBox控件用于显示项目列表。 用户可以通过单击选择一个或多个项目。

listbox.cs

  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. class MForm : Form {
  5. private StatusBar sb;
  6. public MForm() {
  7. Text = "ListBox";
  8. Size = new Size(210, 210);
  9. ListBox lb = new ListBox();
  10. lb.Parent = this;
  11. lb.Items.Add("Jessica");
  12. lb.Items.Add("Rachel");
  13. lb.Items.Add("Angelina");
  14. lb.Items.Add("Amy");
  15. lb.Items.Add("Jennifer");
  16. lb.Items.Add("Scarlett");
  17. lb.Dock = DockStyle.Fill;
  18. lb.SelectedIndexChanged += new EventHandler(OnChanged);
  19. sb = new StatusBar();
  20. sb.Parent = this;
  21. CenterToScreen();
  22. }
  23. void OnChanged(object sender, EventArgs e) {
  24. ListBox lb = (ListBox) sender;
  25. sb.Text = lb.SelectedItem.ToString();
  26. }
  27. }
  28. class MApplication {
  29. public static void Main() {
  30. Application.Run(new MForm());
  31. }
  32. }

我们的示例显示了一个具有六个名称的列表框。 所选项目显示在状态栏中。

  1. ListBox lb = new ListBox();
  2. lb.Parent = this;

ListBox控件已创建。

  1. lb.Items.Add("Jessica");

这就是我们向ListBox控件添加新项目的方式。 该控件具有Items属性。 该属性是对列表框中项目列表的引用。 使用此引用,我们可以添加,删除或获取列表框中的项目数。

  1. lb.SelectedIndexChanged += new EventHandler(OnChanged);

当我们选择一个项目时,会触发SelectedIndexChanged事件。

  1. ListBox lb = (ListBox) sender;
  2. sb.Text = lb.SelectedItem.ToString();

OnChange()方法内部,我们获得对列表框的引用,并将所选文本设置为状态栏。

Mono Winforms 中的高级控件 - 图1

图:ListBox

ListView

ListView控件用于显示项目集合。 它是比ListBox控件更复杂的控件。 它可以在各种视图中显示数据,主要用于在多列视图中显示数据。

listview.cs

  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. using System.Collections.Generic;
  5. public class Actress
  6. {
  7. public string name;
  8. public int year;
  9. public Actress(string name, int year)
  10. {
  11. this.name = name;
  12. this.year = year;
  13. }
  14. }
  15. class MForm : Form {
  16. private StatusBar sb;
  17. public MForm() {
  18. Text = "ListView";
  19. Size = new Size(350, 300);
  20. List<Actress> actresses = new List<Actress>();
  21. actresses.Add(new Actress("Jessica Alba", 1981));
  22. actresses.Add(new Actress("Angelina Jolie", 1975));
  23. actresses.Add(new Actress("Natalie Portman", 1981));
  24. actresses.Add(new Actress("Rachel Weiss", 1971));
  25. actresses.Add(new Actress("Scarlett Johansson", 1984));
  26. ColumnHeader name = new ColumnHeader();
  27. name.Text = "Name";
  28. name.Width = -1;
  29. ColumnHeader year = new ColumnHeader();
  30. year.Text = "Year";
  31. SuspendLayout();
  32. ListView lv = new ListView();
  33. lv.Parent = this;
  34. lv.FullRowSelect = true;
  35. lv.GridLines = true;
  36. lv.AllowColumnReorder = true;
  37. lv.Sorting = SortOrder.Ascending;
  38. lv.Columns.AddRange(new ColumnHeader[] {name, year});
  39. lv.ColumnClick += new ColumnClickEventHandler(ColumnClick);
  40. foreach (Actress act in actresses) {
  41. ListViewItem item = new ListViewItem();
  42. item.Text = act.name;
  43. item.SubItems.Add(act.year.ToString());
  44. lv.Items.Add(item);
  45. }
  46. lv.Dock = DockStyle.Fill;
  47. lv.Click += new EventHandler(OnChanged);
  48. sb = new StatusBar();
  49. sb.Parent = this;
  50. lv.View = View.Details;
  51. ResumeLayout();
  52. CenterToScreen();
  53. }
  54. void OnChanged(object sender, EventArgs e) {
  55. ListView lv = (ListView) sender;
  56. string name = lv.SelectedItems[0].SubItems[0].Text;
  57. string born = lv.SelectedItems[0].SubItems[1].Text;
  58. sb.Text = name + ", " + born;
  59. }
  60. void ColumnClick(object sender, ColumnClickEventArgs e)
  61. {
  62. ListView lv = (ListView) sender;
  63. if (lv.Sorting == SortOrder.Ascending) {
  64. lv.Sorting = SortOrder.Descending;
  65. } else {
  66. lv.Sorting = SortOrder.Ascending;
  67. }
  68. }
  69. }
  70. class MApplication {
  71. public static void Main() {
  72. Application.Run(new MForm());
  73. }
  74. }

在我们的示例中,我们有一个包含两列的列表视图。 在第一列中,我们显示女演员的名字。 在第二个他们的出生日期。 数据存储在List集合中。 通过选择一行,一行中的数据将显示在状态栏中。 另外,通过单击列标题,可以对数据进行排序。

  1. public class Actress
  2. {
  3. ...
  4. }

我们使用Actress类存储数据。

  1. List<Actress> actresses = new List<Actress>();
  2. actresses.Add(new Actress("Jessica Alba", 1981));
  3. actresses.Add(new Actress("Angelina Jolie", 1975));
  4. ...

我们创建项目并在项目中填充项目。

  1. ColumnHeader name = new ColumnHeader();
  2. name.Text = "Name";
  3. name.Width = -1;

对于列表视图中的每一列,我们创建一个ColumnHeader。 通过将Width设置为-1,列的宽度等于列中最长的项目。

  1. ListView lv = new ListView();
  2. lv.Parent = this;

ListView控件已创建。

  1. lv.FullRowSelect = true;
  2. lv.GridLines = true;
  3. lv.AllowColumnReorder = true;
  4. lv.Sorting = SortOrder.Ascending;

在这里,我们设置控件的四个属性。 该代码行支持全行选择,显示网格线,通过拖动列对列进行重新排序并以升序对数据进行排序。

  1. lv.Columns.AddRange(new ColumnHeader[] {name, year});

在这里,我们将两个ColumnHeader添加到ListView控件中。

  1. foreach (Actress act in actresses) {
  2. ListViewItem item = new ListViewItem();
  3. item.Text = act.name;
  4. item.SubItems.Add(act.year.ToString());
  5. lv.Items.Add(item);
  6. }

此循环填充ListView控件。 每行都作为ListViewItem类添加到列表视图。

  1. lv.View = View.Details;

ListView控件可以具有不同的视图。 不同的视图以不同的方式显示数据。

  1. ListView lv = (ListView) sender;
  2. string name = lv.SelectedItems[0].SubItems[0].Text;
  3. string born = lv.SelectedItems[0].SubItems[1].Text;
  4. sb.Text = name + ", " + born;

OnChanged()方法内部,我们从选定的行中获取数据并将其显示在状态栏上。

  1. if (lv.Sorting == SortOrder.Ascending) {
  2. lv.Sorting = SortOrder.Descending;
  3. } else {
  4. lv.Sorting = SortOrder.Ascending;
  5. }

在这里,我们切换列的排序顺序。

Mono Winforms 中的高级控件 - 图2

图:ListView

TreeView

TreeView控件显示项目的分层集合。 此控件中的每个项目都由TreeNode对象表示。

treeview.cs

  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. class MForm : Form {
  5. StatusBar sb;
  6. public MForm() {
  7. Text = "TreeView";
  8. Size = new Size(250, 250);
  9. TreeView tv = new TreeView();
  10. TreeNode root = new TreeNode();
  11. root.Text = "Languages";
  12. TreeNode child1 = new TreeNode();
  13. child1.Text = "Python";
  14. TreeNode child2 = new TreeNode();
  15. child2.Text = "Ruby";
  16. TreeNode child3 = new TreeNode();
  17. child3.Text = "Java";
  18. root.Nodes.AddRange(new TreeNode[] {child1, child2, child3});
  19. tv.Parent = this;
  20. tv.Nodes.Add(root);
  21. tv.Dock = DockStyle.Fill;
  22. tv.AfterSelect += new TreeViewEventHandler(AfterSelect);
  23. sb = new StatusBar();
  24. sb.Parent = this;
  25. CenterToScreen();
  26. }
  27. void AfterSelect(object sender, TreeViewEventArgs e)
  28. {
  29. sb.Text = e.Node.Text;
  30. }
  31. }
  32. class MApplication {
  33. public static void Main() {
  34. Application.Run(new MForm());
  35. }
  36. }

这是TreeView控件的非常简单的演示。 我们有一个根项目和三个子项。

  1. TreeView tv = new TreeView();

我们创建TreeView控件。

  1. TreeNode root = new TreeNode();
  2. root.Text = "Languages";
  3. ...
  4. tv.Nodes.Add(root);

在这里,我们创建一个根节点。

  1. TreeNode child1 = new TreeNode();
  2. child1.Text = "Python";

子节点以类似的方式创建。

  1. root.Nodes.AddRange(new TreeNode[] {child1, child2, child3});

子节点插入到根节点的Nodes属性中。

Mono Winforms 中的高级控件 - 图3

图:TreeView

目录

下面的代码示例将更深入地研究TreeView控件。

directories.cs

  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. using System.IO;
  5. public class MForm : Form
  6. {
  7. private TreeView tv;
  8. private Button expand;
  9. private Button expandAll;
  10. private Button collapse;
  11. private Button collapseAll;
  12. private StatusBar sb;
  13. private const string HOME_DIR = "/home/vronskij";
  14. public MForm()
  15. {
  16. Size = new Size(400, 400);
  17. Text = "Directories";
  18. tv = new TreeView();
  19. SuspendLayout();
  20. tv.Parent = this;
  21. tv.Location = new Point(10,10);
  22. tv.Size = new Size(ClientSize.Width - 20, Height - 200);
  23. tv.Anchor = AnchorStyles.Top | AnchorStyles.Left |
  24. AnchorStyles.Right ;
  25. tv.FullRowSelect = false;
  26. tv.ShowLines = true;
  27. tv.ShowPlusMinus = true;
  28. tv.Scrollable = true;
  29. tv.AfterSelect += new TreeViewEventHandler(AfterSelect);
  30. expand = new Button();
  31. expand.Parent = this;
  32. expand.Location = new Point(20, tv.Bottom + 20);
  33. expand.Text = "Expand";
  34. expand.Anchor = AnchorStyles.Left | AnchorStyles.Top;
  35. expand.Click += new EventHandler(OnExpand);
  36. expandAll = new Button();
  37. expandAll.Parent = this;
  38. expandAll.Location = new Point(20, expand.Bottom + 5);
  39. expandAll.Text = "Expand All";
  40. expandAll.Anchor = AnchorStyles.Left | AnchorStyles.Top;
  41. expandAll.Click += new EventHandler(OnExpandAll);
  42. collapse = new Button();
  43. collapse.Parent = this;
  44. collapse.Location = new Point(expandAll.Right + 5, expand.Top );
  45. collapse.Text = "Collapse";
  46. collapse.Anchor = AnchorStyles.Left | AnchorStyles.Top;
  47. collapse.Click += new EventHandler(OnCollapse);
  48. collapseAll = new Button();
  49. collapseAll.Parent = this;
  50. collapseAll.Location = new Point(collapse.Left, collapse.Bottom + 5);
  51. collapseAll.Text = "Collapse All";
  52. collapseAll.Anchor = AnchorStyles.Left | AnchorStyles.Top;
  53. collapseAll.Click += new EventHandler(OnCollapseAll);
  54. sb = new StatusBar();
  55. sb.Parent = this;
  56. ShowDirectories(tv.Nodes, HOME_DIR);
  57. ResumeLayout();
  58. CenterToScreen();
  59. }
  60. void AfterSelect(object sender, TreeViewEventArgs e)
  61. {
  62. sb.Text = e.Node.Text;
  63. }
  64. void ShowDirectories(TreeNodeCollection trvNode, string path)
  65. {
  66. DirectoryInfo dirInfo = new DirectoryInfo(path);
  67. if (dirInfo != null)
  68. {
  69. DirectoryInfo[] subDirs = dirInfo.GetDirectories();
  70. TreeNode tr = new TreeNode(dirInfo.Name);
  71. if (subDirs.Length > 0)
  72. {
  73. foreach (DirectoryInfo dr in subDirs)
  74. {
  75. if (!dr.Name.StartsWith("."))
  76. ShowDirectories(tr.Nodes, dr.FullName);
  77. }
  78. }
  79. trvNode.Add(tr);
  80. }
  81. }
  82. void OnExpand(object sender, EventArgs e)
  83. {
  84. tv.SelectedNode.Expand();
  85. }
  86. void OnExpandAll(object sender, EventArgs e)
  87. {
  88. tv.ExpandAll();
  89. }
  90. void OnCollapse(object sender, EventArgs e)
  91. {
  92. tv.SelectedNode.Collapse();
  93. }
  94. void OnCollapseAll(object sender, EventArgs e)
  95. {
  96. tv.CollapseAll();
  97. }
  98. static void Main()
  99. {
  100. Application.Run(new MForm());
  101. }
  102. }

我们的代码示例在TreeView控件中显示指定主目录的目录。 该应用启动有些延迟,因为它首先读取主目录的目录结构。 表单上还有四个按钮。 这些按钮以编程方式展开和折叠节点。

  1. tv.Scrollable = true;

我们使TreeView控件可滚动,因为该控件显示了大量目录。

  1. ShowDirectories(tv.Nodes, HOME_DIR);

ShowDirectories()方法使用指定主目录中可用的目录填充TreeView控件的节点。

  1. if (subDirs.Length > 0)
  2. {
  3. ...
  4. }

我们检查是否有任何子目录。

  1. foreach (DirectoryInfo dr in subDirs)
  2. {
  3. if (!dr.Name.StartsWith("."))
  4. ShowDirectories(tr.Nodes, dr.FullName);
  5. }

我们遍历所有目录。 为此,我们使用了递归算法。 我们还跳过隐藏的目录。 它们以 Unix 系统上的点开头。

  1. trvNode.Add(tr);

此代码行实际上将目录添加到TreeView控件。

  1. void OnExpand(object sender, EventArgs e)
  2. {
  3. tv.SelectedNode.Expand();
  4. }

所有四个按钮都将事件插入到方法中。 这是展开按钮的方法。 它调用当前所选节点的Expand()方法。

Mono Winforms 中的高级控件 - 图4

图:Directories

在 Mono Winforms 教程的这一部分中,我们介绍了 Winforms 库中可用的几个高级控件。