复合控件
1.控件的使用综述:在WinForm中使用控件主要包括以下几种情况:
(1)标准控件:直接使用winform自带的控件,比如button、textBox等。我们只需要修改属性,添加事件即可。
(2)复合控件:将一些标准控件组合起来,实现复杂功能。需要定义 class YourControl:UserControl{ }
(3)扩展控件:拓展或者改变一些标准控件的功能。需要继承于标准控件,class YourButton:Button { }
(4)自定义控件:完全自定义一个控件,定义属性、方法、样式等。需要继承于Control(Control是所有控件的基类),class YourControl:Control { }
注意:我们之前学习了标准控件的使用,所以这节课我们就学习一下复合控件如何定义和使用,循序渐进。
2.复合控件:实现一个搜索框控件(组合文本框与图片框):
(1)定义:复合控件又称为用户控件,专门用来将标准控件进行组合,其继承自 UserControl
(2)定义复合控件:
- 右键解决方案->添加 用户控件窗体(UserControl),命名为SearchBox。会自动生成一个SearchBox类,继承自 UserControl
- 双击 SearchBox.cs文件,可以打开设计界面,像窗口一样设计符合组件的样式
a. 拖上去一个textBox文本框作为搜索框
b. 拖上去一个图片框,设置图片为搜索图标
c. 使用表格布局,将二者组合到一起,并调整大小和位置(Anchor、Dock、表格比例等)
d.保存后,重新生成解决方案,再点击界面中的工具箱即可看到我们自己的复合控件
(3)复合控件的摆放和原理
- 在界面中可以直接拖拽符合控件,并且复合控件作为一个整体也具有Size、Location、事件等等常规属性。
- 复合控件本质上就是一个窗体!复合控件中的组件和窗体中的组件一样,在初始化时放置到窗体上。
复合控件SearchBox可视化设计
在SearchBox.cs窗体设计界面中,对复合控件进行可视化样式设计,其步骤如下:
添加一个TableLayoutPanel表格布局容器,保留一行两列。并设置其Dock为Fill填满整个父窗口,然后设置两列表格大小比例为7:3。(用来放置文本框和图片框按钮)
添加一个TextBox到第一个单元格,并设置其Anchor为左右边距固定(可以随父窗口拉伸而拉伸)
添加一个pictureBox到第二个单元格,并设置其Dock为Fill填满单元格,添加图片资源-搜索图标
注意:现在只是设计好了SearchBox的样式,但是还没有设计其属性访问和事件处理,比如复合控件如何获取文本框的值?如何获取/设置图片框的点击事件?复合控件如何当作一个整体来用?
复合控件的属性访问和事件处理
**复合控件的访问和事件处理:我们有时需要获取复合控件内子控件的数据、或者给复合控件的某个位置(图片、按钮)设置事件 **
(1)设置public直接访问(最简单,最直接,最不常用):将复合控件内的子控件成员全部设置为public,直接访问即可
- 在复合控件设计界面内选择每个子控件,设置其 Modifiers 属性为 public (默认为private)
- 然后在复合控件源码中,相关的子控件就会自动变为 public 访问修饰的,我们可以直接使用 [复合控件.子控件.属性] 来访问
- 给SearchBox的搜索图片设置点击事件:searchBox1.pictureBox1.Click += new EventHandler(searchEvent);
- 获取文本框搜索内容:MessageBox.Show(“开始搜索…” + searchBox1.textBox1.Text);
(2)在复合控件内设置事件和获取数据,就可以像窗口一样直接使用子组件了(没试过)
(3)复合控件自定义属性
- 在SearchBox逻辑代码中,添加属性访问器
1 2 3 4 5 6 7 8 9 10 11
| public string SearchText { get { return this.textBox1.Text; } set { this.textBox1.Text = value; } }
|
- 重新生成解决方案,打开Form3界面设计,在杂项中就可以看到我们自定义的属性SearchText。通过修改值可以直接修改内部的TextBox。其本质都是调用了set、get方法。
- 在SearchBox逻辑代码中,重写UserControl已有的属性,比如Text等
1 2 3 4 5 6 7 8 9 10
| public override string Text { get { return this.textBox1.Text; } set { this.textBox1.Text = value; } }
|
- 重新生成解决方案,打开Form3界面设计,原本的属性就成为了我们重写的属性。
- C# Attribute 特性:特性是一种可以被编译器识别的声明性标签,类似于Java的注解
a. 语法:[attribute(positional_parameters, name_parameter = value, …)]
b. 常用特性:
[Browsable(true)]: 控件属性是否在设计器内可见(一般默认为false)
[Category(“Appearance”)]:控件属性显示在哪个类别中。Action(与可用操作相关)、Appearance(与实体的外观相关)、Behavior(与实体的行为相关)、Data(与数据和数据源管理相关)
[DesignerSerializationVisibility()]: 将我们在控件属性上设定的值持久化到代码中,这样我们下次再查看控件的值依然是我们最后一次设定的值。指示一个属性是否串行化和如何串行化,它的值是一个枚举,一共有三种类型Content,Hidden,Visible。
(4)复合控件自定义事件
- 在SearchBox逻辑代码中,添加声明自定义事件。 public event EventHandler SearchEvent;
- 重新生成解决方案后,可以在事件-杂项中看到我们自定义的事件 SearchEvent
- 在设计界面可以给事件添加/实现处理回调方法 onSearch(),配合自定义属性食用
- 在复合组件中,将图片的点击事件 链接到 自定义事件上,即点击图片时触发自定义事件。编写图片的Click事件
1 2 3 4 5 6 7 8 9 10
| private void onClick(object sender, EventArgs e) { if(SearchEvent != null) { SearchEvent.Invoke(this, e); } }
|
注意:一个控件还可以添加多个事件,顺序触发
(1)界面设计
(2)SearchBox.cs 逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| namespace WindowsFormsApp_learning { public partial class SearchBox : UserControl { public event EventHandler SearchEvent;
public SearchBox() { InitializeComponent(); }
public string SearchText { get { return this.textBox1.Text; } set { this.textBox1.Text = value; } }
[Browsable(true)] public override string Text { get { return this.textBox1.Text; } set { this.textBox1.Text = value; } } private void onClick(object sender, EventArgs e) { if(SearchEvent != null) { SearchEvent.Invoke(this, e); } } } }
|
(3)Form3.cs 主窗体逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| namespace WindowsFormsApp_learning {
public partial class Form3 : Form { public Form3() { InitializeComponent(); } private void searchEvent(object sender,EventArgs args) { MessageBox.Show("开始搜索..." + searchBox1.textBox1.Text); } private void onSearch(object sender, EventArgs e) { MessageBox.Show("开始搜索..." + searchBox1.SearchText); } } }
|
二.控件包装
1.控件包装基本设计
1.控件包装:
(1)定义:控件包装是复合控件的一种特殊形式,其内部只有一个控件
(2)目的:对一些基础控件的功能进行拓展和自定义修改,比如TextBox包装后可以修改高度和内边距padding等
(3)步骤:
- 新建包装控件类AfTextBox,继承自UserControl,其内部只放置一个TextBox组件,作为对TextBox的包装拓展
- 为了实现可修改TextBox高度宽度的效果,需要设置TextBox的Size随着外部Form的变化而变化 -> onLayout()
- 为了实现可修改TextBox内边距padding的效果,需要设置Form与TextBox的边距来代替文字内边距 -> onLayout()
- 为了无缝实现上述效果,看着是一个TextBox整体,需要设置TextBox和Form背景色相同,并且取消TextBox边框。
2.Location属性解释:控件左上角相对于其容器左上角的坐标,单位是像素。
(1)对于窗体来说,就是窗口左上角相对于屏幕左上角的坐标;
(2)对于一般控件来说,就是控件左上角相对于其容器左上角的坐标,比如说相对于窗体,图片框等。
(3)父容器左上角默认(0,0)
3.窗口位置调节:
- this.StartPosition = FormStartPosition.Manual; //窗体的位置由Location属性决定
- this.StartPosition = FormStartPosition.CenterParent; //窗体在其父窗体中居中
- this.StartPosition = FormStartPosition.CenterScreen; //窗体在当前显示窗口中居中,尺寸在窗体大小中指定
- this.StartPosition = FormStartPosition.WindowsDefaultBounds; //窗体定位在windows默认位置,边界也由windows默认决定(默认)
- this.StartPosition = FormStartPosition.WindowsDefaultLocation; //窗体定位在windows默认位置,尺寸在窗体大小中指定
(1)TextBox包装控件AfTextBox 逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| namespace WindowsFormsApp_learning { public partial class AfTextBox : UserControl { public AfTextBox() { InitializeComponent(); }
protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); if (this.Controls.Count == 0) return; Control C = this.Controls[0]; Padding p = this.Padding; int x = 0, y = 0; int w = this.Width, h = this.Height; w -= (p.Left + p.Right); x += p.Left; int h2 = C.PreferredSize.Height; if (h2 > h) h2 = h; y = (h - h2) / 2; C.Location = new Point(x, y); C.Size = new Size(w, h2); } } }
|
2.控件包装单文件开发
2.包装、复合控件单文件开发
(1)定义:每次创建UserControl都会自动给我们创建一个相应的designer.cs布局设计文件,将界面和逻辑分开开发。如何将二者合并到一个文件开发呢?
(2)步骤:
- 【手动】创建AfTextBox2普通类 class文件,并手动继承UserControl
- 双击打开AfTextBox2.cs可以进入设计界面,拖放控件。会直接给AfTextBox2.cs内自动添加控件布局(不会分开添加了)
- 手动实现构造函数,初始化调用布局 InitializeComponent()
- 添加逻辑代码和事件、属性
(3)好处:以后可以直接将单个控件cs文件复制到别的项目里直接使用,而不用分多个了
3.包装控件的自定义属性和事件:和复合控件一样(AfTextBox2为例)
(1)添加/重写自定义属性 Text、BackColor、Front
(2)添加自定义事件 ReturnPressed(回车事件)
(1)AfTextBox2包装控件cs逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| namespace WindowsFormsApp_learning { class AfTextBox2 : UserControl {
private TextBox edit;
private void InitializeComponent() { this.edit = new System.Windows.Forms.TextBox(); this.SuspendLayout(); this.edit.BorderStyle = System.Windows.Forms.BorderStyle.None; this.edit.Location = new System.Drawing.Point(106, 79); this.edit.Name = "edit"; this.edit.Size = new System.Drawing.Size(263, 37); this.edit.TabIndex = 0; this.edit.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.OnPress); this.BackColor = System.Drawing.Color.White; this.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.Controls.Add(this.edit); this.Name = "AfTextBox2"; this.Size = new System.Drawing.Size(524, 246); this.ResumeLayout(false); this.PerformLayout(); }
public AfTextBox2() { InitializeComponent(); }
protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); if (this.Controls.Count == 0) return; Control C = this.Controls[0]; Padding p = this.Padding; int x = 0, y = 0; int w = this.Width, h = this.Height; w -= (p.Left + p.Right); x += p.Left; int h2 = C.PreferredSize.Height; if (h2 > h) h2 = h; y = (h - h2) / 2; C.Location = new Point(x, y); C.Size = new Size(w, h2); }
[Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override string Text { get { return edit.Text; } set { edit.Text = value; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override Color BackColor { get { return edit.BackColor; } set { base.BackColor = value; edit.BackColor = value; } }
private Font initFont = new Font("宋体", 10f); [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public override Font Font { get { return initFont; } set { this.initFont = value; this.edit.Font = value; } }
public event EventHandler ReturnPressed; private void OnPress(object sender, KeyPressEventArgs e) { char ch = e.KeyChar; if (ch == '\r') { ReturnPressed?.Invoke(this, e); } } } }
|
(2)Form窗体应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| namespace WindowsFormsApp_learning {
public partial class Form4 : Form { public Form4() { InitializeComponent(); } private void OnEnterPress(object sender, EventArgs e) { MessageBox.Show("正在检索..." + afTextBox21.Font); } } }
|
三.对话框
1.对话框基本概念
1.对话框
(1)构建:对话框本质还是一个Form窗体,只不过以对话框的形式显示。所以对话框的构建参照窗体的设计即可
(2)使用:新建一个对话框 MyDiglog ,在点击事件中显示对话框 ShowDialog()
MyDialog dialog = new MyDialog(); //新建窗体
dialog.ShowDialog(); //作为对话框弹出在当前界面。注意如果是Show()则是显示窗体,非对话框
dialog.Dispose(); //销毁窗体,释放资源
(3)运行流程:
- 在调用ShowDialog方法后,会[阻塞]父窗口进程,不再往下执行。表现为子窗口可以活动,而父窗口不行
- 对话框阻塞直到用户关闭对话框,父窗口进程才继续向下执行
- 执行Dispose方法释放对话框资源
(4)对话框属性(和窗体Form属性一样):
- Text:窗体左上角显示文字
- MaximizeBox:最大化按钮(True显示,Flase不显示)
- MinimizeBox:最小化按钮(True显示,Flase不显示)、
- ShowInTaskBar:是否在任务栏显示
- StartPosition:窗体显示位置 WindowsDefaultLocation窗口默认位置、CenterSceen窗口中央、CenterParent父窗口中央等
- FormBorderStyle:边界样式 Sizable可修改、FixedDialog固定对话框大小、FixedSignle固定窗体
(5)对话框返回值与数据传递
- 对话框含有属性 DialogResult
DialogResult.OK :设置DialogResult为OK,窗体会立即关闭,并返回DialogResult.OK值
DialogResult.Cancel:设置DialogResult为Cancel,窗体会立即关闭,并返回DialogResult.Cancel值
- 数据传递:可以将传递数据组件设置为public,在关闭窗口后Dispose之前调用dialog.xxx来获取属性值
(1)对话框界面设计
**(2)对话框逻辑代码(MyDialog.cs) **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| namespace WindowsFormsApp_learning { public partial class MyDialog : Form { public MyDialog() { InitializeComponent(); } private void OnClickOk(object sender, EventArgs e) { this.DialogResult = DialogResult.OK; } private void OnClickCancel(object sender, EventArgs e) { this.DialogResult = DialogResult.Cancel; } } }
|
(3)Form窗体逻辑代码
1.两大功能:
- 通过点击按钮,创建并展示对话框
- 获取对话框返回值,并显示在主窗体界面上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| namespace WindowsFormsApp_learning { public partial class Form5 : Form { public Form5() { InitializeComponent(); } private void show_Dialog(object sender, EventArgs e) { MyDialog dialog = new MyDialog(); DialogResult res = dialog.ShowDialog(); if(res == DialogResult.OK) { this.textPanel.Text += (dialog.dlg_text.Text + "\r\n"); } dialog.Dispose(); } } }
|
2.快捷操作+默认行为:
- 对话框按钮快捷关闭:按钮上带有一个 DialogResult属性:OK、Cancel等都可以设置。其效果和手写代码是一样的,关闭对话框并返回值
- 对话框的AcceptButton属性:当在对话框点击 回车 时会触发的按钮,默认为None
- 对话框的CancelButton属性:当在对话框点击 ESC 时会触发的按钮,默认为None
2.对话框小练习:字体设置器
要求实现一个文本输入器,可以通过点击按钮弹出字体设置对话框,来选择相应的字体和字号。确认后将主窗口的文本输入变为相应的字体样式。
**(1)主窗口界面设计 **
(2)对话框界面设计
(3)对话框逻辑代码StyleDialog.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| namespace WindowsFormsApp_Demo2 { public partial class StyleDialog : Form { public StyleDialog() { InitializeComponent(); } public string FontType { get { return (string)this.dlg_wordType.SelectedItem; } set { this.dlg_wordType.SelectedItem = value; } } public int FontSize { get { return (int)this.dlg_wordSize.Value; } set { this.dlg_wordSize.Value = value; } } private void onClickOk(object sender, EventArgs e) { this.DialogResult = DialogResult.OK; }
private void onClickCancel(object sender, EventArgs e) { this.DialogResult = DialogResult.Cancel; } } }
|
(4)主窗体逻辑代码Form1.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| namespace WindowsFormsApp_Demo2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void onClickStyle(object sender, EventArgs e) { StyleDialog dlg = new StyleDialog(); DialogResult res = dlg.ShowDialog(); if(res == DialogResult.OK) { string fontType = dlg.FontType; int fontSize = dlg.FontSize; this.text_panel.Font = new Font(fontType, fontSize); } dlg.Dispose(); } } }
|
四.系统对话框
1.系统对话框:WinForm提供了很多内置的系统对话框,比如文件浏览、保存,颜色、字体选择等。
(1)OpenFileDialog : 文件打开对话框
- new OpenFileDialog():新建对话框
- InitialDirectory:设置打开的初始展示路径
- DefaultExt:获取或设置默认显示的文件扩展名。
- Filter:获取或设置当前文件名筛选器字符串。其格式为 “自定义字符串标签|类型列表”
a.单个文件类型:图片|.jpg,.png,.gif
b.多个文件类型:图片|.jpg,.png,.gif|文本|.txt,.doc|所有|.
- FileName:获取或设置对话框中选定的文件名称字符串
- FileNames:获取或设置对话框中所有选定的文件名称字符串列表
(2)SaveFileDialog : 文件保存对话框(跟OpenFileDialog差不多)
(3)FolderBrowserDialog:文件夹选择对话框
- new FolderBrowserDialog():新建对话框
- InitialDirectory: 获取或设置打开的初始路径
- SelectedPath:获取或设置选择的文件夹路径
(4)ColorDialog:颜色选择对话框
(5)FontDialog:字体选择对话框
1.系统对话框功能使用
为了展示系统对话框的功能,此处设计一个文件浏览窗口,能够选择、保存文件或文件夹,并将所选定的文件/目录路径名称展示到主界面文本框。
(1)界面设计
(2)Form.cs逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| namespace WindowsFormsApp_learning { public partial class Form6 : Form { public Form6() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.InitialDirectory = "D:\\日常材料\\学习资料\\WinForm\\第十二章 系统对话框\\12.1 系统对话框\\项目源码\\FormApp1201\\FormApp1201"; fileDialog.DefaultExt = ".cs"; fileDialog.Filter = "代码|*.cs;*.config"; if (fileDialog.ShowDialog() == DialogResult.OK) { string fileName = fileDialog.FileName; this.textBox1.Text = fileName; }
} private void button2_Click(object sender, EventArgs e) { SaveFileDialog dlg = new SaveFileDialog(); dlg.FileName = "新的文本文件"; dlg.DefaultExt = ".txt"; dlg.Filter = "文本|*.txt;*.doc"; if (dlg.ShowDialog() == DialogResult.OK) { string fileName = dlg.FileName; this.textBox1.Text = fileName; } } private void button3_Click(object sender, EventArgs e) { FolderBrowserDialog dlg = new FolderBrowserDialog(); dlg.SelectedPath = Path.GetFullPath("."); if (dlg.ShowDialog() == DialogResult.OK) { string path = dlg.SelectedPath; this.textBox1.Text = path; } } } }
|
2.系统对话框练习-图片查看器
设计一个图片查看器窗口,可以在主窗体中选择浏览目录路径,选择后将该目录下的所有图片名称加载到主窗口左侧的列表栏,用户通过点击列表栏的图片名称可以切换显示相应的图片在主窗口右侧的图片展示区。
(1)界面设计
主窗体中用到了一个自定义文本框AfTextBox,可以自由拉伸。同时有一个浏览按钮放置在其右侧,可以打开文件目录浏览窗口。主窗体还包括一个列表框,用于显示图片名称列表;除此之外还有一个图片框,用于展示指定路径图片。
(2) 自定义对话框AfTextBox单文件开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| namespace WindowsFormsApp_Demo { class AfTextBox:UserControl { private TextBox edit;
private void InitializeComponent() { this.edit = new System.Windows.Forms.TextBox(); this.SuspendLayout(); this.edit.BorderStyle = System.Windows.Forms.BorderStyle.None; this.edit.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.edit.Location = new System.Drawing.Point(52, 52); this.edit.Name = "edit"; this.edit.Size = new System.Drawing.Size(89, 19); this.edit.TabIndex = 0; this.edit.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.onTextPressed); this.BackColor = System.Drawing.Color.White; this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.Controls.Add(this.edit); this.Name = "AfTextBox"; this.Size = new System.Drawing.Size(199, 105); this.ResumeLayout(false); this.PerformLayout(); } public AfTextBox() { InitializeComponent(); } protected override void OnLayout(LayoutEventArgs e) { base.OnLayout(e); if (this.Controls.Count == 0) return; Control c = this.Controls[0]; int w = this.Width, h = this.Height; int x = 0, y = 0; int left = this.Padding.Left, right = this.Padding.Right; w -= (left + right); x += left; int h2 = c.PreferredSize.Height; if (h2 > h) h2 = h; y += (h - h2) / 2; c.Location = new Point(x, y); c.Size = new Size(w, h2); } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override string Text { set { this.edit.Text = value; } get { return this.edit.Text; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override Color BackColor { get { return this.edit.BackColor; } set { this.edit.BackColor = value; base.BackColor = value; } } [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override Color ForeColor { get { return edit.ForeColor; } set { edit.ForeColor = value; } }
[Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool ReadOnly { get { return this.edit.ReadOnly; } set { this.edit.ReadOnly = value; } }
public event EventHandler ReturnPressed; private void onTextPressed(object sender, KeyPressEventArgs e) { char ch = e.KeyChar; if (ch == '\r') { ReturnPressed?.Invoke(this, e); } } } }
|
(3)主窗体Form.cs逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| namespace WindowsFormsApp_Demo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void onScanClick(object sender, EventArgs e) { FolderBrowserDialog dlg = new FolderBrowserDialog(); if(dlg.ShowDialog() == DialogResult.OK) { string path = dlg.SelectedPath; this.afTextbox.Text = path; ShowPictureList(path); }
} private void ShowPictureList(string dir) { listFile.Items.Clear(); string[] files = Directory.GetFiles(dir); foreach(string f in files) { if (f.EndsWith(".jpg") || f.EndsWith(".png") || f.EndsWith(".jpeg")) { PictureListItem item = new PictureListItem(); item.name = Path.GetFileName(f); item.filePath = f; this.listFile.Items.Add(item); } }
if (listFile.Items.Count > 0) listFile.SetSelected(0, true); } private void listFile_SelectedIndexChanged(object sender, EventArgs e) { PictureListItem item = (PictureListItem)listFile.SelectedItem; if (item == null) return; pathPic.Load(item.filePath); } } class PictureListItem { public string name; public string filePath; public override string ToString() { return name; } } }
|
五.菜单栏和工具栏
1.菜单栏 MenuStrip:窗口顶部停靠菜单栏
(1)使用:设计界面可视化设计,可以添加菜单项、下拉框、分割线、文本
(2)属性:每个Item都可以设置ID、Text、Image(图标)、点击事件Click
2.工具栏 ToolStrip:窗口顶部停靠工具栏,一般位于菜单栏下方(图标栏)
(1)使用:设计界面可视化设计,可以添加工具按钮、分割线等。一般窗口上方第一排为菜单栏,第二排为工具栏,二者对应
(2)属性:每个Item都可以设置ID、Image(图标)、点击事件Click等
(3)开发技巧:工具栏与菜单栏一般具有对应关系,每个菜单都有对应的工具图标按钮,二者的点击回调事件可以共用。在事件中点击下拉箭头->选择菜单栏设置的事件即可
3.右键菜单(上下文菜单): ContextMenuStrip
(1)定义:在窗口不同部位右键显示的菜单栏应该具有不同的选项,一般项目中菜单栏和工具栏可能没有,但是右键菜单是一定具有的!
(2)使用:
- 在设计界面添加 ContextMenuStrip上下文菜单,并添加菜单项。但此时仅是对上下文菜单进行了定义和声明,右键还不能显示
- 设置界面或者控件的鼠标点击事件MouseUp/MouseDown,在事件中展示菜单ContextMenuStrip.show(展示控件,展示位置)
- 进一步,我们希望在listBox中,右键item的时候显示编辑和删除,而右键空白位置只显示添加,才符合我们的逻辑(不同的逻辑展示不同的右键菜单内容)
- 设置菜单项点击事件
(1)界面设计
(2)Form.cs逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| namespace WindowsFormsApp_learning { public partial class Form5 : Form { public Form5() { InitializeComponent(); }
private void 打开ToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show("点击了打开..."); } private void listBox1_MouseDown(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Right) { int index = listBox1.IndexFromPoint(e.Location); if (index >= 0) { listBox1.SetSelected(index, true); Item_Edit.Enabled = true; Item_Del.Enabled = true; } else { listBox1.ClearSelected(); Item_Edit.Enabled = false; Item_Del.Enabled = false; } this.contextMenu.Show(listBox1, e.Location); } } private void Item_Add_Click(object sender, EventArgs e) { MessageBox.Show("上下文菜单:选择了添加..."); } } }
|
六.列表视图控件 ListView
1.ListView基本使用
1.列表控件ListView:升级版的ListBox,其显示类似于windows的文件夹视图
(1)特点:列表显示模式可以切换(详情、大图标、小图标),可以多字段显示,可以设置图标、标签可以编辑,每列可以排序,可以自定义设计
(2)控件基本属性:View(显示模式)、Columns(集合,列头名称)、Items(集合,列表中的项)、Items.SubTetms(集合,列表中每项的子项-其他列显示的数据)、LabelEdit(是否允许用户就地编辑标签)、LargeImageList(大图标列表)、SmallImageList(小图标列表)、Sorting(排序方式)等
(3)简单使用步骤:
- 在设计界面将ListView拖入,并设置Dock为占满(接下来可以在设计界面进行可视化设计,也可以通过代码来添加设计数据项)
- 代码方式设计ListView(推荐):
a.设置显示方式
b.设置列名
c.添加数据项
d.设置每个数据项的子项数据
- 推荐使用代码方式添加数据的原因:很多时候我们并不知道要遍历的项有多少,所以不能提前设计好。只能通过代码方式动态添加
(1)ListView基本用法展示
界面设计非常简单,就是拖入一个ListView控件,并设置Dock为Fill填充满父容器,无其他控件,这里就不再展示设计界面了。基本用法主要展示如何在ListView中使用代码方式添加列名、数据项等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| namespace WindowsFormsApp_learning2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); InitializeListView(); }
private void InitializeListView() { listView1.View = View.Details; listView1.FullRowSelect = true; listView1.Columns.Add("文件名",-2,HorizontalAlignment.Left); listView1.Columns.Add("修改时期", 150, HorizontalAlignment.Left); listView1.Columns.Add("类型", 100, HorizontalAlignment.Left); listView1.Columns.Add("大小", -2, HorizontalAlignment.Left); ListViewItem item1 = new ListViewItem("Java学习指南.pdf", 0); item1.SubItems.Add("2020-2-20 12:10"); item1.SubItems.Add("PDF"); item1.SubItems.Add("192 KB"); listView1.Items.Add(item1); } } }
|
(2)ListView基本使用小练习:本地文件目录列表展示
2.ListView控件高级使用:本地文件可视化
(1)在设计界面,将ListView控件拖入,并设置Dock为填充Fill
(2)添加数据项图标的图片资源到Resources
(3)在代码中初始化ListView基本配置,包括列名、显示模式、图标列表等。 InitListView()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| namespace WindowsFormsApp_learning2 {
public partial class Form2 : Form { public Form2() { InitializeComponent(); InitListView(); LoadDir(new DirectoryInfo("D:\\")); } private void InitListView() { listView1.View = View.Details; listView1.FullRowSelect = true; listView1.Columns.Add("名称", -2, HorizontalAlignment.Left); listView1.Columns.Add("修改时间", 150, HorizontalAlignment.Left); listView1.Columns.Add("类型", 100, HorizontalAlignment.Left); listView1.Columns.Add("大小", -2, HorizontalAlignment.Left); ImageList imgList = new ImageList(); imgList.ImageSize = new Size(16, 16); imgList.Images.Add(Properties.Resources.Icon_file); imgList.Images.Add(Properties.Resources.Icon_folder); listView1.SmallImageList = imgList; } private void LoadDir(DirectoryInfo dir) { DirectoryInfo[] subDirs = dir.GetDirectories(); foreach (DirectoryInfo d in subDirs) { if ((d.Attributes & FileAttributes.Hidden) > 0) continue; AddListItem(d.Name, d.LastWriteTime, "文件夹", -1); } FileInfo[] subFiles = dir.GetFiles(); foreach (FileInfo f in subFiles) { if ((f.Attributes & FileAttributes.Hidden) > 0) continue; string ext = f.Extension.ToUpper(); AddListItem(f.Name, f.LastWriteTime, ext, f.Length); } } private void AddListItem(string label, DateTime time, string type, long size) { int imageIndex = 0; if (!type.Equals("文件夹")) imageIndex = 1; ListViewItem item = new ListViewItem(label, imageIndex); item.SubItems.Add(time.ToString("yyyy-MM-dd HH:mm")); item.SubItems.Add(type); string sizeStr = ""; if (size < 0) sizeStr = ""; else if (size < 1000) sizeStr = "" + size; else if (size < 1000000) sizeStr = size / 1000 + " KB"; else if (size < 1000000000) sizeStr = size / 1000000 + " MB"; else sizeStr = size / 1000000000 + " GB"; item.SubItems.Add(sizeStr); listView1.Items.Add(item); } } }
|
2.ListView模式切换
3.ListView控件:模式切换(切换详情、列表、大图标、小图标模式显示)
(1)设计要求:在上节内容文件目录展示案例的基础上,实现右键菜单切换显示模式
(2)开发流程:
- 在设计界面,拖入ListView控件,并设置Dock为充满Fill
- 在代码中初始化ListView控件列名、[大图标列表]、[小图标列表]等(因为大图标模式和小图标模式需要使用两套图标)
- 加载遍历文件和目录,并添加数据项Item
- 在设计界面拖入ContextMenu控件,并设置ListView的MouseUp点击事件,显示右键菜单
- 右键菜单实现切换模式功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| namespace WindowsFormsApp_learning2 {
public partial class Form3 : Form { public Form3() { InitializeComponent(); InitListView(); LoadDir(new DirectoryInfo("D:\\")); } private void InitListView() { listView1.View = View.Details; listView1.FullRowSelect = true; listView1.Columns.Add("名称", -2, HorizontalAlignment.Left); listView1.Columns.Add("修改时间", 150, HorizontalAlignment.Left); listView1.Columns.Add("类型", 100, HorizontalAlignment.Left); listView1.Columns.Add("大小", -2, HorizontalAlignment.Left); ImageList smallImgList = new ImageList(); smallImgList.ImageSize = new Size(16, 16); smallImgList.Images.Add(Properties.Resources.Icon_file); smallImgList.Images.Add(Properties.Resources.Icon_folder); listView1.SmallImageList = smallImgList; ImageList largeImgList = new ImageList(); largeImgList.ImageSize = new Size(64, 64); largeImgList.Images.Add(Properties.Resources.Icon_file2); largeImgList.Images.Add(Properties.Resources.Icon_folder2); listView1.LargeImageList = largeImgList; } private void LoadDir(DirectoryInfo dir) { listView1.BeginUpdate(); DirectoryInfo[] subDirs = dir.GetDirectories(); foreach (DirectoryInfo d in subDirs) { if ((d.Attributes & FileAttributes.Hidden) > 0) continue; AddListItem(d.Name, d.LastWriteTime, "文件夹", -1); } FileInfo[] subFiles = dir.GetFiles(); foreach (FileInfo f in subFiles) { if ((f.Attributes & FileAttributes.Hidden) > 0) continue; string ext = f.Extension.ToUpper(); AddListItem(f.Name, f.LastWriteTime, ext, f.Length); } listView1.EndUpdate(); } private void AddListItem(string label, DateTime time, string type, long size) { int imageIndex = 0; if (!type.Equals("文件夹")) imageIndex = 1; ListViewItem item = new ListViewItem(label, imageIndex); item.SubItems.Add(time.ToString("yyyy-MM-dd HH:mm")); item.SubItems.Add(type); string sizeStr = ""; if (size < 0) sizeStr = ""; else if (size < 1000) sizeStr = "" + size; else if (size < 1000000) sizeStr = size / 1000 + " KB"; else if (size < 1000000000) sizeStr = size / 1000000 + " MB"; else sizeStr = size / 1000000000 + " GB"; item.SubItems.Add(sizeStr); listView1.Items.Add(item); } private void listView1_MouseUp(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Right) { View view = listView1.View; menuDetail_Item.Checked = (view == View.Details); menuList_Item.Checked = (view == View.List); menuLarge_Item.Checked = (view == View.LargeIcon); menuSmall_Item.Checked = (view == View.SmallIcon); contextMenuStrip.Show(listView1, e.Location); } }
private void menuDetail_Item_Click(object sender, EventArgs e) { listView1.View = View.Details; } private void menuList_Item_Click(object sender, EventArgs e) { listView1.View = View.List; } private void menuLarge_Item_Click(object sender, EventArgs e) { listView1.View = View.LargeIcon; } private void menuSmall_Item_Click(object sender, EventArgs e) { listView1.View = View.SmallIcon; } } }
|
3.ListView数据项列排序
4.ListView的列排序实现:点击每一列可以实现升序/降序排序(此处只以第0列为例)
(1)编码步骤(在文件目录展示案例的基础上):
- 添加箭头图标资源,表示升序和降序标识
- 将图标加入SmallImageList,其中Images.Add (key, image ) 表示添加一个图像image,并关联一个key值。后面可以根据key值获取此图片。
- 添加数据项Tag:每个ListView可以关联一个Tag,一般为一个对象。用于排序的时候便于直接使用对象做比较
- 定义比较器MyListItemSorter,实现绑定Tag对象的自定义排序
- 添加列的点击事件:ColumnClick 切换升序/降序
(1)自定义Tag对象,封装信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| namespace WindowsFormsApp_learning2 { class MyListItemTag { public int type = 0; public string path; public string name; public DateTime time; public long size = -1; public string ext;
public MyListItemTag(int type, string path, string name, DateTime time, long size, string ext) { this.type = type; this.path = path; this.name = name; this.time = time; this.size = size; this.ext = ext; } } }
|
(2)自定义比较器,实现对象排序(传入两个Tag对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| namespace WindowsFormsApp_learning2 { public class MyListItemSorter : IComparer { public bool asc = true;
public MyListItemSorter(bool asc) { this.asc = asc; } public int Compare(object x, object y) { ListViewItem item1 = (ListViewItem)x; ListViewItem item2 = (ListViewItem)y; MyListItemTag tag1 = (MyListItemTag)item1.Tag; MyListItemTag tag2 = (MyListItemTag)item2.Tag; if (tag1.type != tag2.type) return CompareInt(true, tag1.type, tag2.type); return CompareStringIgnoreCase(asc, tag1.name, tag2.name); } public int CompareBool(bool asc, bool x, bool y) { int xx = x ? 1 : 0; int yy = y ? 1 : 0; return CompareInt(asc, xx, yy); } public int CompareInt(bool asc, int x, int y) { if (asc) return x - y; else return y - x; } public int CompareString(bool asc, string x, string y) { if (asc) return x.CompareTo(y); else return y.CompareTo(x); } public int CompareStringIgnoreCase(bool asc, string x, string y) { return CompareString(asc, x.ToLower(), y.ToLower()); } } }
|
**(3)主窗体Form.cs逻辑代码 **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| namespace WindowsFormsApp_learning2 { public partial class Form4 : Form { private bool asc = true; public Form4() {
InitializeComponent(); InitListView(); LoadDir(new DirectoryInfo("D:\\")); } private void InitListView() { listView1.View = View.Details; listView1.FullRowSelect = true; listView1.Columns.Add("名称", -2, HorizontalAlignment.Left); listView1.Columns.Add("修改时间", 150, HorizontalAlignment.Left); listView1.Columns.Add("类型", 100, HorizontalAlignment.Left); listView1.Columns.Add("大小", -2, HorizontalAlignment.Left); ImageList imgList = new ImageList(); imgList.ImageSize = new Size(16, 16); imgList.Images.Add(Properties.Resources.Icon_file); imgList.Images.Add(Properties.Resources.Icon_folder); listView1.SmallImageList = imgList; imgList.Images.Add("Sort_ASC", Properties.Resources.up); imgList.Images.Add("Sort_DESC", Properties.Resources.down); listView1.Columns[0].ImageKey = "Sort_ASC"; } private void LoadDir(DirectoryInfo dir) { listView1.BeginUpdate(); DirectoryInfo[] subDirs = dir.GetDirectories(); foreach (DirectoryInfo d in subDirs) { if ((d.Attributes & FileAttributes.Hidden) > 0) continue; MyListItemTag tag = new MyListItemTag(0,d.FullName,d.Name,d.LastWriteTime,-1,"文件夹"); AddListItem(tag); } FileInfo[] subFiles = dir.GetFiles(); foreach (FileInfo f in subFiles) { if ((f.Attributes & FileAttributes.Hidden) > 0) continue; MyListItemTag tag = new MyListItemTag(1, f.FullName, f.Name, f.LastWriteTime, f.Length, f.Extension.ToUpper()); AddListItem(tag); } listView1.EndUpdate(); } private void AddListItem(MyListItemTag tag) { int imageIndex = 0; if (!tag.type.Equals("文件夹")) imageIndex = 1; ListViewItem item = new ListViewItem(tag.name, imageIndex); item.Tag = tag; item.SubItems.Add(tag.time.ToString("yyyy-MM-dd HH:mm")); item.SubItems.Add(tag.ext); long size = tag.size; string sizeStr = ""; if (size < 0) sizeStr = ""; else if (size < 1000) sizeStr = "" + size; else if (size < 1000000) sizeStr = size / 1000 + " KB"; else if (size < 1000000000) sizeStr = size / 1000000 + " MB"; else sizeStr = size / 1000000000 + " GB"; item.SubItems.Add(sizeStr); listView1.Items.Add(item); } private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) { if (e.Column == 0) { this.asc = !asc; if (asc) { listView1.ListViewItemSorter = new MyListItemSorter(true); listView1.Sort(); listView1.Columns[0].ImageKey = "Sort_ASC"; } else { listView1.ListViewItemSorter = new MyListItemSorter(false); listView1.Sort(); listView1.Columns[0].ImageKey = "Sort_DESC"; } } } } }
|
4.ListView标签编辑
5.ListView:编辑标签
(1)设计ListView显示,并添加数据项
(2)在设计界面或代码中设置LabelEdit=True,表示允许对数据项标签进行编辑
(3)标签编辑的启动方式:
- 在窗口中双击标签,启动编辑
- 使用代码方式,在事件中使用 ListViewItem.BeginEdit() 来启动编辑(比如右键菜单-重命名 事件):
a.添加右键菜单,新建菜单项-重命名
b.ListView添加MouseUp鼠标点击事件,显示右键菜单,获取右键点中的项
c.右键菜单项添加鼠标点击事件,点击右键菜单-重命名,开启该项的标签编辑
d.编辑验证:在编辑之后/之前,进行标签内容的验证(比如不能重复名称,不能包含某些字符等),在ListView中添加事件BeforeLabelEdit/AfterLabelEdit,开启对每个数据项的编辑验证(自动在编辑前后触发)
(4)注意:
- 只能对主项进行编辑
- 标签编辑默认不会修改源数据(比如文件显示不会修改真实文件名称),要想同步修改可以设置事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| namespace WindowsFormsApp_learning2 { public partial class Form5 : Form { private ListViewItem mouseClickItem;
public Form5() { InitializeComponent(); InitListView(); AddListItem(new Student(20201001, "shao", "13810012xxx")); AddListItem(new Student(20201002, "wang", "18799122xxx")); AddListItem(new Student(20201003, "li", "13490912xxx")); } private void InitListView() { listView1.View = View.Details; listView1.FullRowSelect = true; listView1.LabelEdit = true; listView1.Columns.Add("姓名", 150, HorizontalAlignment.Left); listView1.Columns.Add("学号", 150, HorizontalAlignment.Left); listView1.Columns.Add("手机号", -2, HorizontalAlignment.Left); } private void AddListItem(Student stu) { ListViewItem item = new ListViewItem(stu.Name, 0); item.Tag = stu; item.SubItems.Add(stu.Id + ""); item.SubItems.Add(stu.Phone); listView1.Items.Add(item); } private void listView1_MouseUp(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Right) { ListViewItem item = listView1.GetItemAt(e.X, e.Y); this.mouseClickItem = item; renameMenu_Item.Enabled = (item != null); contextMenuStrip1.Show(listView1, e.Location); } } private void renameMenu_Item_Click(object sender, EventArgs e) { this.mouseClickItem.BeginEdit(); } private void listView1_BeforeLabelEdit(object sender, LabelEditEventArgs e) { } private void listView1_AfterLabelEdit(object sender, LabelEditEventArgs e) { int index = e.Item; string label = e.Label; for (int i = 0; i < listView1.Items.Count; i++) { if (index == i) continue; if (label == listView1.Items[i].Text) { e.CancelEdit = true; MessageBox.Show("名字重复", "提示"); return; } } e.CancelEdit = false; Student stu = (Student)listView1.Items[index].Tag; stu.Name = label; } } }
|
七.表格视图控件 DataGridView
1.表格视图基本用法
1.表格视图 DataGridView 基础: 以单元格表格的形式展示数据和操作
(1)在设计界面,拖入DataGridView控件,并设置Dock为填满Fill
(2)在设计界面或代码中,设置列名Columns
(3)在设计界面或代码中添加数据项,推荐代码添加(动态拓展)
注意:表格视图的每一单元格应都是可编辑的!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| namespace WindowsFormsApp_learning2 { public partial class Form6 : Form { public Form6() { InitializeComponent(); InitGridView(); AddRows(new Student(202101, "wx", "18264886xxx")); AddRows(new Student(202102, "my", "13012459xxx")); AddRows(new Student(202103, "tom", "19857138xxx")); }
private void InitGridView() { this.dataGridView1.ColumnCount = 4; dataGridView1.Columns[0].Name = "学号"; dataGridView1.Columns[1].Name = "姓名"; dataGridView1.Columns[2].Name = "性别"; dataGridView1.Columns[3].Name = "手机号"; } private void AddRows(Student stu) { Object[] row = { stu.Id,stu.Name,"男",stu.Phone }; dataGridView1.Rows.Add(row); } } }
|
2.表格视图高级用法
2.表格视图 DataGridView 基本操作:属性、增删改查
(1)DataGridView 常用属性:
- [杂项] Columns : 设置列相关的列数、列名等
- [外观] ColumnHeadersVisible : 设置列头是否可见(默认为True)
- [外观] RowHeadersVisible : 设置行的头是否可见(默认为True)
- [行为] MultiSelect : 是否允许多项选择(默认为True)
- [行为] AllowUserToxxx:是否允许用户对单元格进行 增删改查等修改
- [行为] 列还支持点击 升序/降序 排序(自动已实现)
(2)DataGridView 常用操作:
- 添加一行数据:grid.Rows.Add(Object[]) 或 界面手动添加(需要触发事件,持久化到数据库)
- 获取行数据:
a.索引方式:grid[col,row] 注意是列索引在前,行索引在后
b.函数方式:grid.Rows[i].Cells[j]
- 删除行数据:
a.单行删除:grid.Rows.RemoveAt(int i):删除第i行数据
b.多行删除(ctrl多选):grid.Rows.Remove(DataGridViewRow row):删除指定的row对象
3.表格视图 DataGridView 单元格编辑
(1)实现方式:
- 界面直接编辑:DataGridView默认每个单元格都是可以直接编辑的,编辑修改后按下回车即可将修改显示到界面中。
- 添加事件触发编辑:也可以通过添加右键菜单或双击事件来进行编辑,或者弹出对话框编辑。
(2)相关属性:ReadOnly
- 设计界面:Columns中,设置某列为ReadOnly=True只读,不能被编辑修改;ReadOnly=False可编辑
- 代码中:grid.Columns[0].ReadOnly = True;
(3)单元格编辑事件步骤:
- 设置状态:设置ReadOnly = False 可编辑状态(默认为False)
- 启动编辑:界面中点击单元格选中,再点击一次,则启动进入编辑状态
- 编辑后的验证事件:当编辑完成按下回车时,触发 [焦点] CellValidating 单元格验证时发生,CellValidating 执行完成后 触发CellValidated 单元格验证后发生
(1)案例界面设计
设计一个案例,实现对表格视图的基本操作(增删改查),以及编辑事件验证。
(2)Form.cs主窗体逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| namespace WindowsFormsApp_learning2 { public partial class Form7 : Form { public Form7() { InitializeComponent(); InitGridView(); AddRows(new Student(202101, "wx", "18264886xxx")); AddRows(new Student(202102, "my", "13012459xxx")); AddRows(new Student(202103, "tom", "19857138xxx")); }
private void InitGridView() { this.grid.ColumnCount = 4; grid.Columns[0].Name = "学号"; grid.Columns[1].Name = "姓名"; grid.Columns[2].Name = "性别"; grid.Columns[3].Name = "手机号"; } private void AddRows(Student stu) { Object[] row = { stu.Id,stu.Name,"男",stu.Phone }; grid.Rows.Add(row); } private void btn_add_Click(object sender, EventArgs e) { Object[] row = new object[4]; row[0] = 202104; row[1] = "testUser"; row[2] = "女"; row[3] = "1928373838"; grid.Rows.Add(row); } private void btn_get_Click(object sender, EventArgs e) { Object id = grid[0, 0].Value; Object name = grid[1, 0].Value; Object sex = grid.Rows[0].Cells[2].Value; Object phone = grid.Rows[0].Cells[3].Value; MessageBox.Show(id + "," + name + "," + sex + "," + phone); } private void btn_del_Click(object sender, EventArgs e) { foreach(DataGridViewRow row in grid.SelectedRows) { grid.Rows.Remove(row); } } private void grid_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { if (e.ColumnIndex == 1) { }else if (e.ColumnIndex == 2) { } else if(e.ColumnIndex == 3) { string str = e.FormattedValue.ToString(); if(str.Length != 11) { MessageBox.Show("手机号必须为11位", "Error"); e.Cancel = true; return; } foreach(char ch in str) { if(ch < '0' || ch > '9') { MessageBox.Show("手机号必须为数字", "Error"); e.Cancel = true; return; } } } } private void grid_CellValidated(object sender, DataGridViewCellEventArgs e) { } } }
|
八.综合练习:学生信息管理系统
相关链接
- WinForm(二) WinForm进阶与复杂控件使用
=================我是分割线=================
欢迎到公众号来唠嗑: