- 第一章 程序介绍
- 1、C#的运行环境——.NET
- .NET
- .NET Framework
- .CLR 公共语言运行环境
- 公共语言规范 (CLS)
- 公共类型系统 (CTS)
- .NET 类库
- 2、C#的特点
- 3、程序的输入和输出
- 第二章 C#语法基础
- 数据类型
- 简单值类型
- 整数类型
- 小数类型
- 字符类型
- 布尔类型
- 枚举类型
- 结构体类型
- 引用类型
- 字符串类型
- 对象类型
- 运算符
- 标识符和关键字
- 注释和惯例
- 运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 控制语句
- 分支语句
- 循环语句
- 跳转语句
- 第三章 类与对象
- 字段、属性、方法
- 构造方法和析构方法
- 方法的重载
- 对象的创建和使用
- 修饰符
- 访问控制符
- const修饰符
- readonly 修饰符
- readonly与const的区别
- 静态成员(修饰符)
- sealed、abstract
- 继承修饰符(n、v、o)
- ref、out
- as运算符
- 继承-封装-多态-作用域
- 接口
- this、base关键字
- 异常处理
- 委托、事件
- 委托(多播)
- 事件
- 范例
- 泛型
- 数组、集合
- 数组
- ArrayList(顺序表)
- 实例
- HashTable(哈希表)
- 实例
- 伪随机数类
- 第四章 窗体、控件
- 窗体
- 属性
- 事件
- 方法
- 控件
- label
- TextBox
- Button
- RadioButton(单选按钮)
- CheckBox
- GroupBox和Panel控件
- ListBox和ComboBox
- ImageList控件
- ListView
- TreeView
- ProgressBar
- MonthCalendar
- Timer控件
- Date TimePicker
- DataGridView
- 菜单
- MenuStrip
- ContentMenuStrip
- 鼠标键盘事件
- 鼠标
- 实例演示
- 键盘
- 操作介绍
- 三项区别
- 实例演示
- 对话框
- MessageBox
- FontDialog
- ColorDialog
- FolderBrowserDiaglog
- OpenFileDialog
- SaveFileDialog
- 应用程序
- SDI、MDI
- 第五章 GDI+
- GDI+概述
- 图形绘制结构、类
- Point PointF
- Size SizeF
- Rectangle RectangleF
- Graphics类
- 绘图成员
- 实例——矩形、图形
- 图像类
- Bitmap类
- Pen类
- Brush类
- Color结构
- Font类
- 坐标变换
- 背景色和前景色
- 第六章 文件管理
- 文件操作
- Directory(info)类
- File和FileInfo类
- Path类
- 实例
- 文件流-读写
- 第七章 数据库
- 四个包含对象
- **DataAdapter的读取数据步骤**
- DataReader读取步骤
- 实例演示
.NET 是基于Windows平台的技术,包含所有的编程语言
- .NET 框架 (. NET Framework)
- . NET 语言(C# C++ F# )
- 开发工具(visual studio)
大体框架
.NET Framework.NET 框架是一个创建、部署、运行应用系统的多语言平台环境语言
.CLR 公共语言运行环境 公共语言规范 (CLS)规定所有的.NET语言都遵行的规则
公共类型系统 (CTS)包含标准数据类型
.NET 类库-
基础数据类库
-
文件输入/输出
-
数据访问
-
XML解析
-
安全控制
……
- 支持多线程
- 限制指针的使用
- 自动内存分配、垃圾回收
console.read()——读入一个字符(按下enter结束)
console.readline()——读入一行字符串
console.write()——输入一个数据或一个字符串
console.writeline()——输入一个字符串并且换行
int.parse()、double.parse()、Convert.Toint()等等都可以进行强制类型转换
C#语言源代码文件的后缀名是( .cs )
第二章 C#语法基础 数据类型
值类型的数据存放在内存栈
引用类型的引用存放在内存栈 ,实际数据存放在内存堆里面
内存栈——运算效率快
内存堆——运算效率慢
简单值类型 整数类型
short-16
int-32
long-64
……
一般采取的是十进制和十六进制,十进制为默认的,十六进制的需要增加0x,例如0x2F——47
无符号的整数需要增加U——32U
长整数——16L
小数类型 float-32
double-64
decimal-128
双精度小数的double可以省略,系统默认是双精度数字
字符类型存放两个字节
char-16
布尔类型 bool-8
枚举类型以下的例子应该新增个类会好些的,但是基本框架是这样的
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
public class EnumConversionExample
{
public static void Main()
{
Season a = Season.Autumn;
//等价于 Season a; a = Season.Autumn
Console.WriteLine(a); // Autumn
}
}
结构体类型
暂且认为等价于类
不能给成员变量赋值
struct Student
{
public string name;
public char sex;
public int age;
}
class Program
{
static void Main(string[] args)
{
//定义⼀个学⽣变量
Student xiaoming = new Student();
//学⽣结构内变量赋值
xiaoming.name = "xiaoming";
xiaoming.age = 16;
xiaoming.sex = 'M';
}
}
引用类型
字符串类型
字符是值类型,字符串是引用类型
string
对象类型装箱:将值类型的变量转换成引用类型的对象的过程
拆箱:将引用类型的对象转换成值类型的过程
转换方法
- Convert.ToXXX目标类型(原始变量)方法
- XXX .Parse(原始变量)方法
- 使用XXX .ToString()方法
- is运算符:检查对象是否与给定类型兼容
- as运算符:用于执行引用各类型的显示类型转换
- typeof运算符:判断的类型必须是具体的类名、类型名称,不可以是变量名称
标识符和关键字
-
标识符的构成字母、数字、下划线、unicode字符组成
-
开头不能是数字
-
不能与关键字重名,区分大小写
-
允许标识符以@作为前缀
@在c#中作为取消转移的符号存在,一般必须放在引号的前面
@ "\server\sexy" // 等价于 "\\server\\sexy"
惯例:
- 类名、属性名、方法名应该大写,采用驼峰法
- 接口的名字,加上I
- 局部变量和参数变量一般小写
注释:
- //用于当行注释
- 用于多行注释
- /// 文档注释
运算符 算术运算符
- +——加法
- ’-‘——减法
- “*”——乘法
- “/"——除法
- ”%“——取余
- ++、–
大于、小于,等于等等……
逻辑运算符&是逻辑运算符——计算两个值
|是逻辑运算符——计算两个值
&&是条件运算符——fasle,就取第一个,
||是条件运算符——true,就取第一个
控制语句 分支语句if、else语句
switch语句
switch (表达式){
case 判断值;一系列操作;break;
case 判断值;一系列操作;break;
case 判断值;一系列操作;break;
case 判断值;一系列操作;break;
default :一系列值 ;break;
}
int trydo1 = int.Parse(Console.ReadLine());
switch (trydo1)
{
case 1: Console.WriteLine('1');break;
default:Console.WriteLine("其他");break;
}
表达式里面的值必须是整数型、字符类型、枚举类型;判断值必须是常数,不能是变量或者表达式
循环语句- while循环
- do-while循环
- for循环
- foreach循环
foreach(数据类型 变量 in 几何/数组){
// 语句块
}
//注意,每个遍历项只是可读的,不做修改的
for( ; ;){
//做一些操作
……
}
//这里是无条件执行,永远不会退出
跳转语句
break、continue
第三章 类与对象
类:相同特征、相同行为的对象
对象:某一些类的实例
字段、属性、方法字段:表示事物的性质,例如age、name等等——小公主
属性:指定执行和声明对相关成员的读/写——保姆/管家
方法:类所具有的方法,对内部变量的操作,小括号是方法的标志——执行操作的人
public class Student{
private int age;
private string name;
public int Age{
get{
return age;
}
set{
name = value;
}
}
public void Do(){
Console.Writeline(this.name+"需要现在做作业了");
}
}
构造方法和析构方法
构造方法:是一种特殊的方法、与类同名的方法,专门用于创建对象——初始化(砌家工程师)
- 可以有一个或者多个构造方法
- 方法名与类名相同
- 没有返回值
- 可以带着参数
- 具有修饰符,如果是private,则用于单例设计模式
- 不能直接调用,必须通过new运算符
析构方法:释放对象所用到的方法——看后门/推土机
- 没有返回值也没有修饰符
- 不带参数
- 与类同名
- 需要~作为开头
- 不能显式调用
- 最多就一个析构函数
public class Student{
private int age;
public int Age{
get{
return age;
}
set{
name = value;
}
}
// 构造方法
public Student(age){
this.Age = age;
}
// 析构方法
~ Student{
……
}
}
方法的重载
可以对普通方法、构造方法的重载
两同两不同
- 相同的类名
- 相同的方法名
- 不同的参数类型
- 不同的参数个数
注意点:
- int类型可以去找double类型进行重载,因为int转换成double不会丢失数据——向上查找(不丢失信息)
- 也被称为静态多态,编译器根据签名的不同而进行不同的操作
- 方法重载的返回类型可以不一样
class SumUtils
{
public string name;
public int age;
// 构造方法的重载
public SumUtils(int age){
this.age = age;
}
public SumUtils(string name){
this.name = name;
}
// 普通方法的重载
public int Sum(int a,int b)
{
return a + b;
}
public double Sum(double a,double b)
{
return a + b;
}
public string Sum(string a,string b)
{
return a + b;
}
}
class Program
{
static void Main(string[] args)
{
SumUtils s = new SumUtils();
Console.WriteLine("两个整数的和为:" + s.Sum(3, 5)); // 8
Console.WriteLine("两个小数的和为:" + s.Sum(3.2, 5.6)); // 8.8
Console.WriteLine("连个字符串的连接结果为:" + s.Sum("C#", "方法重载")); // C#方法重载
}
}
对象的创建和使用
先声明 再对其实例化 使用
Students a = new Students(); a.方法名; a.属性名; ……
注意点
- 对象是引用类型,所以不同的对象(在同一个类声明出来的)也会存在不同的地址上(完全独立)
- 只能通过对象变量进行访问
分为public、protected internal、protected、internal、private
基于逻辑——protected表示子类可以访问
基于物理——internal表示同一个程序集可以访问
- public 无限制访问
- protected internal 同一个程序集或子类可以访问
- protected 同类及其子类可以访问
- internal 同一个程序集可以访问,但是非子类的也还是不可以的
- private 仅在同类里可以访问
注意点:
类的声明默认是internal,类的成员(方法等)声明默认是private
const修饰符- 类的成员进行const修饰,默认的修饰符是static
一般形式——修饰符 const 类型 常量名 = 表达式
- 局部变量修饰,不加别的修饰符
class Student{
private const int age = 2;
public void Do(){
const a =2;
}
}
readonly 修饰符
只读字段声明为 readonly 关键字。
readonly与const的区别**静态常量(Const)**是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值。
**动态常量(Readonly)**的值则是在运行的那一刻才获得的,编译器编译期间将其标示为只读常量,而不用常量的值代替,这样动态常量不必在声明的时候就初始化,而可以延迟到构造函数中初始化。
- Const修饰的常量在声明的时候必须初始化;Readonly修饰的常量则可以延迟到构造函数初始化 。
- Const常量既可以声明在类中也可以在函数体内,但是Static Readonly常量只能声明在类中。Const是静态常量,所以它本身就是Static的,因此不能手动再为Const增加一个Static修饰符。
- Const修饰的常量在编译期间就被解析,即:经过编译器编译后,我们都在代码中引用Const变量的地方会用Const变量所对应的实际值来代替; Readonly修饰的常量则延迟到运行的时候。
[C#基本知识点-Readonly和Const的区别 - 梦在前方 - 博客园 (cnblogs.com)](https://www.cnblogs.com/daidaibao/p/4214268.html#:~:text=Const的变量是嵌入在IL代码中,编译时就加载好,不依赖外部dll(这也是为什么不能在构造方法中赋值)。,Const在程序集更新时容易产生版本不一致的情况。 Readonly的变量是在运行时加载,需请求加载dll,每次都获取最新的值。)
静态成员(修饰符)
使用static进行修饰
- 静态字段
- 静态属性
- 静态方法
注意点
- static 的执行顺序会先于main()函数的
- 静态成员的意思是**不属于某个实例的,而是整个类的,**整个类的所有实例都是共享的,会存放在静态数据区
- 同样都在静态里面的话,值的赋值可以不用类名
class Student{
int a;
static int b;
static void Do(){
// a=2;
b=3;
}
void Doing(){
a=2;
b=3;
}
}
class Student {
static int age; // 静态字段
static int Age{ // 静态属性
get{
return age;
}
set{
age = value;
}
}
// 静态方法
public static void Do(){
Age = 2;
Console.Writeline(age);
}
}
sealed、abstract
sealed类——对类的封装,说明这个类不可能有子类,无法被继承
abstract类——抽象类,这个对象不能被实例化,但是可以被继承,意义在于公共属性的集合
注意
- 抽象类可以有构造函数,这些构造函数可以被子类的构造函数所调用
- 抽象方法只需要声明,用到分号,不需要括号
- 抽象方法必须在子类中实现,除非子类也是抽象类
- 含有abstract的方法的类就是abstract类
- 密封不能使用在静态成员上
//抽象类
public abstract class Student{
//抽象方法
abstract int Do();
//抽象属性
abstract string name{
get;
set;
}
}
// sealed类1
public sealed class Int(){
private int age;
public int Age{
……
}
……
}
继承修饰符(n、v、o)
new 方法——直接隐藏父类同名、同签名的成员,而新定义一个成员
virtual方法——虚方法,里面书写了内容,可以被子类覆盖(override),也可以保留
override——覆盖,在子类实现abstract、virtual 的时候就必须使用override方法
public abstract class Bird
{
private string name;
public string Name
{
get{
return name;
}
set{
name = value;
}
}
public Bird(string str){ //接受子类传来的参数进行构造化
Name = str;
}
public abstract void Eat();
public virtual void Drink()
{
Console.WriteLine("我会喝水哦");
}
}
public class Eagle:Bird
{
private string intro;
public int age;
public string Name{
get{
return intro;
}
set{
intro = value;
}
}
public Eagle(int age,string name):base(name)
{
this.age = age;
}
public override Eat(){
Console.WriteLine("我喜欢吃肉的");
}
public override Drink(){
Console.WriteLine("我喜欢喝饮料");
}
}
public class Program
{
static void Main(string[] args)
{
Bird b = new Eagle(20,"乌鸦");
//个人认为可行的原因在于子类有着父类的构造方法,所以可以用子类的方法进行修饰父类
b.Eat(); //输出的结果是我喜欢吃肉-子类的方法
b.Drink(); //输出的结果是我喜欢喝饮料,如果去掉子类的方法,父类的方法也是可以实现的
}
}
动态多态:方法的动态绑定,方法体的调用时,在程序的执行时动态决定的
base方法也无法调用私有的父类方法
ref、out首先:两者都是按地址传递的,使用后都将改变原来参数的数值。
其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所以你必须初始化一次。这个就是两个的区别,或者说就像有的网友说的,ref是有进有出,out是只出不进。
ref(C# 参考)
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
例如:
class RefExample
{
static void Method(ref int i)
{
i = 44;
}
static void Main()
{
int val = 0;
Method(ref val);
// val is now 44
}
}
传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。
尽管 ref 和 out 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:
class CS0663_Example
{
// Compiler error CS0663: "cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(ref int i) { }
public void SampleMethod(out int i) { }
}
但是,如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两个参数,则可以进行重载,如下例所示:
class RefOutOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(ref int i) { }
}
out(C# 参考)
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用out 关键字。
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int value;
Method(out value);
// value is now 44
}
}
尽管作为 out 参数传递的变量不必在传递之前进行初始化,但需要调用方法以便在方法返回之前赋值。
ref 和 out 关键字在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(out int i) { }
public void SampleMethod(ref int i) { }
}
但是,如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两类参数,则可以进行重载,如下所示:
class RefOutOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(out int i) { }
}
下面是本人的一些心得:
区别:
ref和out的区别在C# 中,既可以通过值也可以通过引用传递参数。通过引用传递参数允许函数成员更改参数的值,并保持该更改。若要通过引用传递参数, 可使用ref或out关键字。ref和out这两个关键字都能够提供相似的功效,其作用也很像C中的指针变量。它们的区别是:
1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。
2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。
3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。
out
方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
当希望方法返回多个值时,声明 out 方法非常有用。使用 out 参数的方法仍然可以返回一个值。一个方法可以有一个以上的 out 参数。
若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。
不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。
属性不是变量,不能作为 out 参数传递。
ref是 有进有出,而out是 只出不进。
[C#中out和ref之间的区别 - 石shi - 博客园 (cnblogs.com)
as运算符-----------------as运算符用于引用类型的转换-------------------
相对于显式转换的优势是
- 不会出现异常,如果出现不能转换的类型,运算的结果是null
//假设 student是person的子类
Person p =new Person();
Student s = new Student();
Person x = s as Person; //ok
Student y = p as Student; //ok
Student z = p as Teacher; //null
object obj1 = "this is a string";
object obj2 = 9;
string str1 = obj1 as string; // 转换成功
Console.WriteLine("str1:" + str1);
string str2 = obj2 as string; // 转换失败
Console.WriteLine("str2:" + str2);
Console.ReadLine();
继承-封装-多态-作用域
封装——把数据和处理的代码封装到一个类中
继承——从现有的类中继承派生 新类的功能
C#仅仅支持单继承
多态——一个功能的多重实现
静态多态通过方法的重载实现的
动态多态通过方法的动态绑定
类的初始化顺序
- 先变量后构造函数。变量先被初始化,然后构造函数被执行。
- 先静态化后实例化。当一个类被访问时,静态变量和构造函数最先被初始化。接着是对象的实例化变量和构造函数被初始化。
- 先派生类后基类(实例构造函数除外)。
具体的例子就看上面的例子,基本全部实现了
接口接口:用于定义一组抽象操作的集合,通常为一些抽象的方法和属性——更加抽象的东西
public interface Ifly
{
void Add();
int Count{get;};
}
子接口也可以继承父接口的所有属性——也可以使用new修饰符屏蔽父类元素
一个类只能继承一个类,但是可以"实现"多个接口
注意:
- 接口的方法都是默认为public,类在实现接口的方法的时候也需要用public
- 不会实现任何东西,没有字段,只有属性和方法
- 没有构造函数、析构函数
public interface IAnimal
{
void Behavior();
}
public class Dog:IAnimal
{
string ActiveTime = "白天";
//如果私有的方法,那么程序就会报错,必须x
public void Behavior()
{
Console.WriteLine("晚上睡,白天活动");
}
}
this、base关键字
this——当前的对象
base——指向基类
base的作用处
- 在派生类中实现对基类成员的访问——base.age
- 调用基类中已被其他方法重写的方法——base.method
- 创建派生类实例时调用基类构造方法——(xx):base(xx)
注意点
- 可以引用父类的字段、属性等等,但是不能访问父类修饰符为private的字段等。
public class People{
private int age;
public int Age{
get{
return age;
}
set{
age = value;
}
}
public People(int age){
Age = age;
}
public virtual void Do(){
Console.WriteLine("Hello");
}
}
public class Student:People{
private string name;
public Student(string name,int a):base(a){
//用到了this的遮挡效果
this.name = name;
}
public override void Do(){
//调用父类的构造方法
base.Do();
Console.WriteLine("world");
}
}
public class Program
{
static void Main(string[] args)
{
People a = new Student("姚俊杰", 20);
a.Do(); //输出的是hello world
}
}
this的作用处
- 限定被相似名称隐藏的成员
- 将对象作为参数传到其他的方法
- 声明索引器
注意点
- this 不能引用静态变量
- 在static方法中,不能使用this关键字
try{}、catch{}、Finnally{}
try——可能出现错误的代码
catch——出现异常后的执行的代码
Finnally——无论如何都会执行的代码
try {
//可能出错的代码
}
catch{
//出现异常后执行的代码
}
finally{
//都会执行的代码
}
委托、事件 委托(多播)
委托——定义了方法的类型,将方法名作为方法的参数
public delegate void Hello(string a); //声明方式 Hello d = new Hello(函数名/方法名); //委托实例化,注意,这个方法名返回的类型需要与Hello的一致
寻找的是参数类型、个数、返回类型一样的方法作为委托
委托调用的时候,不必关心该方法的对象的类型,只要求提供的方法的签名与委托的签名一样即可
(个人理解)可以理解为是一个自定义的参数类型+“重载”,他会自动去匹配与本身参数一样的函数,都作为自己的”方法“,然后另外的函数在使用的时候,就可以先找委托,然后运行委托内部的一个方法
public delegate void GreetingDelegate(string name);
class Program {
private static void EnglishGreeting(string name) {
Console.WriteLine("Morning, " + name);
}
private static void ChineseGreeting(string name) {
Console.WriteLine("早上好, " + name);
}
//注意此方法,它接受一个GreetingDelegate类型的方法作为参数
private static void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}
static void Main(string[] args) {
GreetPeople("yjj", EnglishGreeting); //个人认为此处使用了语法糖,因为把英语付给make,一般都是new //这里不报错,因为c#的简写支持(语法糖),下面也是如此
GreetPeople("yjj", ChineseGreeting);
//输出两个
}
}
ps:网上说委托也是一个类,会在编译的时候初始化,所以建议放在类的外面,但杨老师都是写在里面,自行斟酌
事件
事件—— 一个类和另外一个类之间传递信息或者触发新的行为的一种编程方法
public event 委托类型名 事件名; //事件的声明
委托与事件步骤
- 声明一个委托
public delegate void BoilHandler();
- 声明一个委托类型的事件
public event BoilHandler BoilEvent; //声明事件,定义在heater类中
- 编写事件的处理方法
public void MakeAlert(int param)
{
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
- 将事件和事件处理方法联系(绑定)起来
//事件字段+=new 委托名(方法名); heater.BoilEvent += alarm.MakeAlert; //注册方法 heater.BoilEvent += Display.ShowMsg; //注册静态方法
- 调用触发事件的函数
BoilEvent(tem);范例
namespace Delegate
{
// 热水器
public class Heater
{
private int temperature;
public delegate void BoilHandler(int param); //声明委托
public event BoilHandler BoilEvent; //声明事件
// 烧水
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
if (temperature > 95) {
if (BoilEvent != null) { //如果有对象注册
BoilEvent(temperature); //调用所有注册对象的方法
}
}
}
}
}
// 警报器
public class Alarm
{
public void MakeAlert(int param)
{
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
}
// 显示器
public class Display {
public static void ShowMsg(int param)
{ //静态方法
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
}
class Program
{
static void Main()
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.BoilEvent += alarm.MakeAlert; //注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.BoilEvent += Display.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
C# 理解委托与事件(烧水壶例子) - zhengwei_cq - 博客园 (cnblogs.com)
可以再看一遍这篇文献,介绍了为何委托,以及事件的由来,初看不知意,再看赞不已
总结(比较扩展的,些许深奥,我自己的见解)
- 事件event是对于委托类型的再一次封装,声明一个进行了封装的委托类型的变量而已
- 允许在不同类中同时绑定对应的方法,无需在主函数内声明多个类
- event声明的事件无法使用=,因为它总是被声明为private,不管是不是声明为public,外部无权访问
- 只需记住事件所绑定的方法,跟他的委托类型有关即可
泛型
定义:泛化的数据类型,引入类型参数的概念——只生成特定的数据类型——冰棍模具
优点
- 代码复用性好——减少代码的书写量
- 性能更高——无需封装
- 安全性更好——最多编译报错,而不是运行出错
约束条件——作用在泛型之处,不是含有泛型类型的地方
class Pwhere Tf:struct { //错误泛型 public void Do(T n1) where T:struct public void Do (T n1) where T:struct //另起炉灶 }
- where T:struct——必须为值类型
- where T:class——引用约束,必须是引用类型的数据
- where T:new()——构造函数约束,必须为无参数的构造函数
- where T:基类名——T必须是指定的基类或者派生类
- where T:接口名——T必须是指定的接口或者实现指定接口
class Student{ private Tfirst age; private Tsecond name; public Student(Tfirst age,Tsecond name) { this.age = age; this.name = name; } public void Do(Tfirst n) { Console.WriteLine("总和为{0}",n); //Console.WriteLine("总和为{0}",n+age); //泛型类型和泛型类型无法相加,即使类型一样 } //泛型方法的使用、约束使用 public void Swap (ref T a,ref T b) where T:struct { T temp = a; a = b; b = temp; } } class Program { static void Main(string[] args) { Student a = new Student (20,"yjj"); a.Do(20); //输出20的结果 int b, c; b = 2; c = 10; a.Swap (ref b,ref c); //成功交换值——ref要求是地址 char d, e; d = 'a'; e = 'b'; a.Swap(ref d, ref e); //两种方法等价,编译器会自动识别 a.Swap (ref d, ref e); //交换的是字符类型 } }
数组、集合 数组
数组是相同类型数据、有序数据的集合
int []Array = new int[5]{1,2,3,4,5}; //未{},则初值为0
int []Array = new int[]{1,2,3,4,5}
int []Array = {1,2,3,4,5}; //三个方式等价
//可以使用数组名.length 获得数组的长度
//多维数组的声明
int [,]A = new int[2,2]{{1,2},{3,4}};
int [,]A = {{1,2},{3,4}};
int [,,]A = new int[3,4,5];
集合的分类
- ArrayList(顺序表)
- Queue(队列)
- Hashtable(哈希表)
- Stack(栈)
- SortedList(有序表)
放入不同的数据,跟数组区别,”动态数组“
using System.Collections; //导入命名空间
ArrayList list = new ArrayList();
ArrayList list = new ArrayList(7); //指定长度
Student student1 = new Student("姚俊杰",20);
list.Add(student1);
list.Remove(对象名); //删除指定对象名的对象
list.RemoveAt(index); //删除指定索引的对象
list.Clear(); //清空
//遍历 list.Count()会获得个数
foreach(Object a in list)
{
……
}
List则是泛型类的动态数组,可以增删改查,区别于普通的数组,存放一类的数据,区别于ArrayList。
实例
class Program
{
class Person
{
private string name;
private string IDnumbers;
private int age;
public string Name
{
get { return name; }
set { name = value; }
}
public string IDNumbers
{
get { return IDnumbers; }
set { IDnumbers = value; }
}
public int Age
{
get { return age; }
set { age = value; }
}
public Person(string name,string Id,int age)
{
this.name = name;
IDnumbers = Id;
this.age = age;
}
}
static void Main(string[] args)
{
List list1 = new List();
list1.Add(new Person("张三", "001", 18));
Person p2=new Person("李四", "002", 19);
list1.Add(p2);
list1.RemoveAt(0);
}
}
HashTable(哈希表)
根据键可查到相应的值,键与值一一对应
任意两个键不能相同,存入的顺序是随机的,无序的
Dictionary是泛型的键值对,跟上面的List一样
Hashtable ht = new Hashtable();
ht.Add(键,值);
ht.Remove(关键字);
ht.Clear();
//遍历
//遍历方法一:遍历哈希表中的键——keys
foreach(string key in ht.Keys)
{
//Console.WriteLine(string.Format("{0}-{1}"), key, ht[key]);
Console.WriteLine(string.Format("{0}-{1}", key, ht[key]));
}
Console.WriteLine("**********************************************************");
//遍历方法二:遍历哈希表中的值——values
foreach(string value in ht.Values)
{
Console.WriteLine(value);
}
Console.WriteLine("**********************************************************");
实例
class Program
{
class Student
{
int number;
string name;
public int Number
{
get { return number; }
set { number = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
}
static void Main(string[] args)
{
// list的使用
List list_Student = new List();
Student s1 = new Student();
s1.Name = "张三";
s1.Number = 1;
Student s2 = new Student();
s2.Name = "李四";
s2.Number = 2;
list_Student.Add(s1);
list_Student.Add(s2);
Console.WriteLine(list_Student[0].Name); //张三
// dictionary的使用
Dictionary dic = new Dictionary();
dic.Add(1, s1);
dic.Add(2, s2);
Student s3 = new Student();
s3.Name = "王五";s3.Number = 3;
if (! dic.ContainsKey(3)) //判断集合中是否含有某个键
{
dic.Add(3, s3);
}
Dictionary.KeyCollection x = dic.Keys; //键的集合
Dictionary.ValueCollection y = dic.Values; //值的集合
foreach (KeyValuePair i in dic) //pair 记录一个键/值对这样的值
{
Console.WriteLine(i.Key + i.Value.Name);
}
foreach (int i in x) //x为键的集合
{
Console.WriteLine(i);
}
foreach (Student3 i in y) //y为值的集合
{
Console.WriteLine(i.Name);
}
}
}
伪随机数类
Random 类是一个产生伪随机数字的类,它的构造函数有两种。
New Random(); New Random(Int32)。
前者是根据触发那刻的系统时间做为种子,来产生一个随机数字
后者可以自己设定触发的种子。
Random类
| 方法 | 描述 |
|---|---|
| Next() | 每次产生一个不同的随机正整数 |
| Next(int max Value) | 产生一个比 max Value 小的正整数 |
| Next(int min Value,int max Value) | 产生一个 minValue~maxValue 的正整数,但不包含 maxValue |
| NextDouble() | 产生一个0.0~1.0的浮点数 |
| NextBytes(byte[] buffer) | 用随机数填充指定字节数的数组 |
正是由于根据系统时间作为种子,所以程序产生的随机数是可以相同的,所以被称为伪随机数类
for (int i = 0; i < 6; i++)
{
Random random = new Random();
Console.WriteLine(random.Next());
}
Console.ReadKey();
//可以选择在构造的时候传入不同的参数,实现多个随机数
for (int i = 0; i < 6; i++)
{
Random random = new Random(i);
Console.WriteLine(random.Next());
}
Console.ReadKey();
第四章 窗体、控件 窗体 属性
- 窗体的大小
- 标题文本的内容
- 背景颜色
| 属性 | 作用 |
|---|---|
| Name | 用来获取或设置窗体的名称 |
| WindowState | 获取或设置窗体的窗口状态,取值有3种,即Normal(正常)、Minimized(最小化)、Maximized(最大化),默认为 Normal,即正常显示 |
| StartPosition | 获取或设置窗体运行时的起始位置,取值有 5 种,即 Manual(窗体位置由 Location 属性决定)、CenterScreen(屏幕居中)、WindowsDefaultLocation( Windows 默认位置)、WindowsDefaultBounds(Windows 默认位置,边界由 Windows 决定)、CenterParent(在父窗体中居中),默认为 WindowsDefaultLocation |
| Text | 获取或设置窗口标题栏中的文字 |
| MaximizeBox | 获取或设置窗体标题栏右上角是否有最大化按钮,默认为 True |
| MinimizeBox | 获取或设置窗体标题栏右上角是否有最小化按钮,默认为 True |
| BackColor | 获取或设置窗体的背景色 |
| BackgroundImage | 获取或设置窗体的背景图像 |
| BackgroundImageLayout | 获取或设置图像布局,取值有 5 种,即 None(图片居左显示)、Tile(图像重复,默认值)、Stretch(拉伸)、Center(居中)、Zoom(按比例放大到合适大小) |
| Enabled | 获取或设置窗体是否可用 |
| Font | 获取或设置窗体上文字的字体 |
| ForeColor | 获取或设置窗体上文字的颜色 |
| Icon | 获取或设置窗体上显示的图标 |
- Load——加载窗体事件
- FormClose——关闭窗口事件
- Activate——窗体被代码激活事件
- Click——点击或双击窗体的客户区事件
- Paint——在窗体上绘制事件——在永久绘图上,这个就很有用的
- show()——显示窗体
- Close()——关闭窗体
- CenterToScreen()——在屏幕中央打开窗体
- Hide()——隐藏窗体
控件 label
标签控件——用于展示文本或者图像信息
- Text:展示文本内容
- Font: 设置label控件所用的字体
- ……
——用于提供输入和输出的可编辑控件
- Text——显示文本数据的属性
- ReadOnly——控制用户是否可以在运行时修改文本框的内容
按钮控件——创建click事件处理程序响应用户单击按钮
- FlatStyle——定义Button控件实例的外观
- Click——点击事件,调用处理该事件的函数
单选按钮
- Checked——指示控件是否被选中
- FlatStyle——确定控件实例的外观
- ……
多项选择的复选框,以及描述复选框作用的文本
- Checked——只是改复选框是否被选中
- ……
二者都是容器控件
ListBox和ComboBoxListBox
- Items:列表框中的项
- SelectedIndex——被选中的索引编号
- SelectedItem——返回当前选中项
- ……
ComboBox
- DropDownStyle——判断组合框的类型
- MaxDropDownItems——最多显示的项数
二者都是选择一个或者多个项目,都是可以窗体的小暂停按钮进行编辑项操作(方便些)
区别是一个是下拉,一个是固定
ImageList控件存放一组照片,每一个控件中的图片大小必须一致
ListViewListView分别用图标、小图标、列表或报表的不同视图展示数据
TreeView树形图由节点和连接线组成
- SelectedNode——获取设置当前选定的树节点
- ExpandAll——张开节点的所有子节点
- ……
进度条控件——从左至右显示程序进度
| 属性 | 类型 | 用法 |
|---|---|---|
| Visible | bool | 获取或设置进度条控件可见还是不可见 |
| Minimum | int | 获取或控件范围的最小值,默认为0 |
| Maximum | int | 获取或控件范围的最大值,默认为100 |
| Value | int | 获取或设置进度栏当前位置,默认为0 |
| Step | int | 获取或设置调用 PerformStep() 方法增加进度栏进度的步长,默认值为 10。 |
private void startProgress()
{
// 显示进度条控件.
pBar1.Visible = true;
// 设置进度条最小值.
pBar1.Minimum = 1;
// 设置进度条最大值.
pBar1.Maximum = 15;
// 设置进度条初始值
pBar1.Value = 1;
// 设置每次增加的步长
pBar1.Step = 1;
// 循环执行
for (int x = 1; x <= 15; x++)
{
// 执行PerformStep()函数
pBar1.PerformStep();
}
pBar1.Visible = false;
MessageBox.Show("success!");
}
private void button1_Click(object sender, EventArgs e)
{
startProgress();
}
[C# ProgressBar 进度条控件_渐进的冰山的博客-CSDN博客_c# progressbar](
日期显示,占着大格子的那个,很不常用
Timer控件定时控件
Timer 控件的Interval属性,用来指定时钟空间触发时间的时间间隔,单位毫秒。
设置日期时间的控件
DataGridView可以自己新建,也可以选择数据库连接
菜单 MenuStrip
弹出式菜单
- Checked——菜单选项可以具有复选框的功能
- Enable——菜单选项是否启用
- Text——菜单选项的文本
- ToolTipText:鼠标悬停提示文本信息
- Click——点击事件
- ……
直接输入
ContentMenuStrip鼠标右键弹出的快捷菜单
注意:与窗体中的ContextMenuStrip属性进行绑定
private void Form1_Load(object sender, EventArgs e)
{
this.ContextMenuStrip = contextMenuStrip2; //这里就是老师上课说的绑定,如果在窗体右键,那么就在窗体下面设置,
//如果是在别的地区,就在别的控件下面设置右键属性,每个地区的右键属性可以是不一样的
}
鼠标键盘事件 鼠标
- MouseDown——按下鼠标按钮时的事件
- MouseEnter——鼠标光标首次进入控件区触发的事件
- MouseHover——鼠标光标离开控件区域时触发的事件
- MouseLeave——鼠标移开空间区域触发的事件
- MouseMove——鼠标移入控件区域触发的事件
- MouseUp——鼠标位于控件上释放鼠标键
Down(按下)——Click(按下松开瞬间)——Up(抬起触发)
鼠标属性
- Button——获取鼠标按下哪个快键
- Click——获取鼠标按下释放的次数
- Position——获取鼠标点击的位置
注意:
click,可以不用鼠标点.(当焦点在些控件上,你点回车之类的就可以激发这个事件)mouseclick就得用鼠标点.**
在MouseDown、Up等等下面进行鼠标按键选择,不是Click,姚某踩过坑过(# ̄~ ̄#)——只要看e有没有Button也可以判断
实例演示public partial class MouseKey : Form
{
// 初始化新的窗口
public MouseKey()
{
InitializeComponent();
}
// 鼠标进入事件
private void MouseKey_MouseEnter(object sender, EventArgs e)
{
richTextBox1.AppendText("鼠标进入enter了窗体范围.n");
}
//鼠标移开事件
private void MouseKey_MouseLeave(object sender, EventArgs e)
{
richTextBox1.AppendText("鼠标离开leave了窗体范围.n");
}
//鼠标悬停事件
private void MouseKey_MouseHover(object sender, EventArgs e)
{
richTextBox1.AppendText("鼠标悬停hover了窗体范围.n");
}
//鼠标按下
private void MouseKey_MouseDown(object sender, MouseEventArgs e)
{
//鼠标三键操作!!!!!!!!!!!!!!!!!!!!!!!!!!
if (e.Button==MouseButtons.Right)
richTextBox1.AppendText("右键操作!!!!!!!!!!!.n");
if (e.Button == MouseButtons.Middle)
richTextBox1.AppendText("中键操作!!!!!!!!!!!n");
if (e.Button == MouseButtons.Left)
richTextBox1.AppendText("左键操作!!!!!!!!!!!n");
}
//鼠标移动
private void MouseKey_MouseMove(object sender, MouseEventArgs e)
{
richTextBox1.AppendText("鼠标move" + e.X + ", " + e.Y + "n");
}
//鼠标弹起
private void MouseKey_MouseUp(object sender, MouseEventArgs e)
{
richTextBox1.AppendText("鼠标弹起up了窗体范围.n");
}
//鼠标点击事件
private void MouseKey_Click(object sender, EventArgs e)
{
richTextBox1.AppendText("鼠标点击click了窗体范围.n");
}
}
键盘
- KeyDown——按下键盘任意一个键时触发的效果
- KeyPress——每次按下并且释放时触发事件(一直按着,一直触发)
- KeyUp——释放键盘任意一键时发生的事件
主要属性
- Alt——指示是否同时按下Alt键
- Control——是否同时按下Control键
- Handled——指示是否处理次事件
- KeyCode——获取KeyDown或KeyUp事件的键盘代码
- Shift——指示是否同时按下Shift键
- ……
//键盘按下操作
private void richTextBox2_KeyDown(object sender, KeyEventArgs e)
{
richTextBox1.AppendText("输入code-data-value是:"+e.KeyCode+","+e.KeyData+","+e.KeyValue+"n");
}
//键盘点击操作
private void richTextBox2_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar ==(char) Keys.A)
{
richTextBox1.AppendText("键盘输入code,data,value的");
}
}
//键盘松开操作
private void richTextBox2_KeyUp(object sender, KeyEventArgs e)
{
richTextBox1.AppendText("键盘松开了");
}
三项区别
- 三个事件的顺序
先KeyDown,再KeyPress,最后KeyUp。
2.KeyDown触发后,KeyUp是否一定触发
KeyDown触发后,不一定触发KeyUp,当KeyDown 按下后,拖动鼠标,那么将不会触发KeyUp事件。
3.三个事件的定义
按下,点下、释放
4.三者的区别
KeyPress主要捕获数字,无法捕获shift、alt等特殊的键,其余两个都是可以捕获(除了Prscrn)
KeyPress只捕获单字符,可以捕获大小写
KeyDown、Up不区分大小写,其KeyValue都是一样的
……
5.如何使用组合键
通过KeyUp 事件能够来处理
(这里说明一下为什么不用KeyDown,因为在判定KeyDown的时候,CTRL、SHIFT和ALT 属于一直按下状态,然后再加另外一个键是不能准确捕获组合键,所以使用KeyDown 是不能准确判断出的,要通过KeyUp 事件来判定 )
private void Form3_KeyUp(object sender, KeyEventArgs e)
{
if (e.Control)
{
MessageBox.Show("KeyUp:Ctrl+" + e.KeyValue.ToString());
}
}
实例演示
private void Form3_KeyUp(object sender, KeyEventArgs e)
{
if ((Control.ModifierKeys & Keys.Control) == Keys.Control ) //判断Ctrl键
if ((Control.ModifierKeys & Keys.Control) == Keys.Control && e.KeyCode == Keys.V)//判断Ctrl+V键
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) //判断Shift键
if ((Control.ModifierKeys & Keys.Alt) == Keys.Alt) //判断Alt键
}
// 这种组合键的,一般使用的是KeyCode——因为是多个组合键配合 e.KeyCode ==Keys.v 和 组合键
//而在press中,使用的是KeyChar——单个键,所以是char,判断的话直接使用字符类型 e.KeyChar == ’T‘
private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 'T' || e.KeyChar=='t')
{
string a = richTextBox1.Text;
int b = 0, i = 1;
while (i < a.Length)
{
if ((int)a[i] > 128)
{
b++;
}
i++;
}
MessageBox.Show("总共的长度为" + b);
}
}
C#键盘事件处理(来源网上) - _ali - 博客园 (cnblogs.com)
总结:鼠标注意三键不在click,键盘输入注意单还是组合键
对话框 MessageBox
消息框控件——静态类,通过MessageBox.Show()
输入的参数顺序为:消息内容、标题、按钮类型、图标类型
按钮类型
- OK
- OKCancel
- YesNo
- YesNoCance
- ……
图标类型
- Error、Hand、Stop——手状符号
- Question——问号图标
MessageBox.Show("hsdghshgdshgdghs"); //直接调用静态,立即执行显示内容的方法
DialogResult c= MessageBox.Show("这文本内容","标题",MessageBoxButtons.OKCancel,MessageBoxIcon.Error);
//进行判断的方法
if(c == DialogResult.OK)
{
richTextBox1.BackColor = fd.Color;
}
FontDialog
字体对话框控件
常见属性
- Color——设置对话框颜色属性
- Font——设置字体对话框的字体属性
- ……
FontDialog fd = new FontDialog();
DialogResult a = fd.ShowDialog();
if (a == DialogResult.OK)
{
richTextBox1.Font = fd.Font;
}
ColorDialog
颜色对话框控件
tips:修改richtext的前景色既是修改文档的字体颜色
ColorDialog cd = new ColorDialog();
DialogResult a = cd.ShowDialog();
if (a == DialogResult.OK)
{
richTextBox1.BackColor = cd.Color;
}
FolderBrowserDiaglog
浏览文件夹下载对话框控件——选择文件夹而不是文件
FolderBrowserDialog fbd = new FolderBrowserDialog();
//将会修改弹出路径的窗口的名字
fbd.SelectedPath = "D:\"; //设置初始化打开的路径
fbd.ShowNewFolderButton = true; //显示“新建文件夹”按钮
fbd.Description = "快来看我看我看我看我看我"; //描述性语句
fbd.ShowDialog();
//fbd.RootFolder="C:\Users";
DialogResult dr = fbd.ShowDialog();
if (dr == DialogResult.OK)
{
richTextBox1.Text = fbd.SelectedPath;
}
OpenFileDialog
打开文件对话框控件——读路径
OpenFileDialog pfd = new OpenFileDialog();
DialogResult a = pfd.ShowDialog();
if (a == DialogResult.OK)
{
richTextBox1.Text = pfd.FileName;
}
属性
- FileName——保存用户选择的文件夹
- Fileter——保持当前的过滤器
用法:
标签名|*.后缀名(过滤器)
saveFileDialog1.Filter = "txt文件(*.txt)|*.txt|所有文件(*.*)|*.*";SaveFileDialog
浏览文件对话框控件
SaveFileDialog pfd = new SaveFileDialog();
DialogResult a = pfd.ShowDialog();
if (a == DialogResult.OK)
{
richTextBox1.Text = pfd.FileName;
}
应用程序
SDI、MDI
SDI——单文档界面——记事本程序
MDI——多文档界面——Excel
单文档的意思并不是说只有一个窗体,而是说这些窗体都是独立存在的,不会相互影响,而多文档程序并不是相互独立的,他们会有父窗体,限制在父窗体里面。
注意事项
- 窗体的IsMdiContainer的属性设置为True——父元素设置为可以是多个子菜单组成
- ChildForm.MdiParent=this——子元素指向父元素
- LayOutMdi(MdiLayOut.Cascade)——定义父元素的排列顺序
//MDI 实例
public MDI()
{
InitializeComponent(); //默认是True
this.IsMdiContainer = true;
}
private void MDI_Load(object sender, EventArgs e)
{
Form1 f1 = new Form1(); //注意,这里的new的时候不要跟窗体一样,要不然会报错
f1.Text = "第一个窗体";
f1.MdiParent = this;
f1.Show();
Form1 f2 = new Form1();
f2.Text = "第二个窗体";
f2.MdiParent = this;
f2.Show();
}
private void button1_Click(object sender, EventArgs e)
{
this.LayoutMdi(MdiLayout.TileVertical); //垂直
}
private void button2_Click(object sender, EventArgs e)
{
this.LayoutMdi(MdiLayout.TileHorizontal); //水平
}
private void button3_Click(object sender, EventArgs e)
{
this.LayoutMdi(MdiLayout.Cascade); //块联
}
private void button4_Click(object sender, EventArgs e)
{
this.LayoutMdi(MdiLayout.ArrangeIcons); //排列
}
第五章 GDI+ GDI+概述
GDI负责系统与绘图程序之间的信息交换,使得程序员无需关心硬件设备及驱动
命名控件——System.Drawing
System.Drawing.Drawing2D
GDI+——只需创建一个Graphics对象,即可使用
图形绘制结构、类 Point PointF二者表示平面上的一个点(X,Y),都是结构
Point p = new Point(0,0); PointF p = new PointF(50.5f,60.4f);Size SizeF
表示矩形区域的大小(无法绘制矩形,缺少点,可以绘制好多的图形)——结构
Size s = new Size(400,300); Point p = new Point(100,200); Size s2 = new Size(p);Rectangle RectangleF
定义了一个矩形区域——结构类型
Rectangle(Point p,Size s); Rectangle(x,y,width,height);Graphics类
要使用Graphics类,三种获得Graphics的方式
- Windows窗体或者控件的paint事件获得Grahics对象
- 使用Form类的CreateGraphics方法
- 继承图像的任何对象创建Graphics对象
//window获取方式——e为PaintEventArgs,如果不是,嗯,自求多福
Graphics p = e.Graphics;
//创建模式
Graphics g = this.CreateGraphics();
//继承图像创建的对象
Bitmap images = new Bitmap("1.bmp");
Graphics g = Graphics.FromImage(images);
绘图成员
- DrawArc——绘制弧线
参数是(笔,矩形,起始角度,扫射角度)——扫射角度
//获取g对象 Graphics g = CreateGraphics(); Pen p = new Pen(Color.GreenYellow, 2); Point p1 = new Point(20, 40); Size s1 = new Size(300, 300); Rectangle r1 = new Rectangle(p1, s1); g.DrawArc(p, r1, 45, 45); //扫射角度和初始角度 g.Dispose();
- DrawEllipse ——绘制椭圆
参数(笔,外接矩阵)
//获取g对象 Graphics g = CreateGraphics(); Pen p = new Pen(Color.Blue, 2); Point p1 = new Point(20, 40); Size s1 = new Size(300, 300); Rectangle r1 = new Rectangle(p1,s1); //画圆 g.DrawEllipse(p, r1); g.Dispose();
-
DrawImage——绘制图形
-
DrawLine——绘制线
//获取g对象 Graphics g = CreateGraphics(); Pen p = new Pen(Color.Red,2); Point p1 = new Point(10, 10); Point p2 = new Point(50, 50); //画直线 g.DrawLine(p, p1, p2); g.Dispose();
- DrawPie——绘制圆形分格统计图
//获取g Graphics g = CreateGraphics(); Pen p = new Pen(Color.Black, 3); Point p1 = new Point(20, 40); Size s1 = new Size(300, 300); Rectangle r1 = new Rectangle(p1, s1); g.DrawPie(p, r1, 45, 45); g.Dispose();
- DrawPloygon——绘制多边形
//获取g
Graphics g = CreateGraphics();
Pen p = new Pen(Color.Red, 1);
Point[] pts = new Point[] { new Point(30, 40), new Point(60, 30), new Point(90, 40),new Point(60,100) };
g.DrawPolygon(p, pts);
g.Dispose();
参数是画笔和点集合数组
- DrawRectangle——绘制矩形
- DrawString——绘制字符串
参数是文本内容、字体、画刷、位置
SolidBrush br = Brushes.Blue;
Font fnt =new Font("Tahoma",25,FontStyle.Regular);
g.DrawString("hello world",fnt,br,50,50);
- FillPie/FillPloygon/FillRectangle——填充图形表、多边形、矩阵
//获取g对象——图形表绘制
Graphics g = CreateGraphics();
//Pen p = new Pen(Color.Black, 3);
SolidBrush ss = new SolidBrush(Color.Red);
Point p1 = new Point(20, 40);
Size s1 = new Size(300, 300);
Rectangle r1 = new Rectangle(p1, s1);
g.FillPie(ss, r1, 45, 45);
g.Dispose();
//绘制多边形
Graphics g = CreateGraphics();
LinearGradientBrush ss = new LinearGradientBrush(new Point(60,10), new Point(60, 100),Color.Red,Color.Blue);
//一个点是渐变色的起点,一个是渐变色的终点。
Point[] pts = new Point[] { new Point(30, 40), new Point(60, 30), new Point(90, 40), new Point(60, 100) };
g.FillPolygon(ss, pts);
g.Dispose();
- DrawPath——绘制容器的类
Graphics g = CreateGraphics();
//生成一个路径对象,存放所要绘制的路径
GraphicsPath gp = new GraphicsPath();
Pen p = new Pen(Color.Red, 2);
Point[] pts = new Point[] { new Point(30, 40), new Point(60, 30), new Point(90, 40), new Point(60, 100) };
gp.AddPolygon(pts);
Point p1 = new Point(20, 40);
Size s1 = new Size(300, 300);
Rectangle r1 = new Rectangle(p1, s1);
gp.AddEllipse(r1);
//这里绘制了两个图形,一个是点集合的多边形,一个是椭圆——所以说他是容器
g.DrawPath(p,gp); //一个参数是画笔,一个是GraphicsPath(绘制路径)
g.Dispose();
实例——矩形、图形
private void button1_Click(object sender, EventArgs e)
{
//获取g对象!!!!!!!!!!!!
Graphics g = this.CreateGraphics();
Pen p = new Pen(Color.Red, 5);
Point p1 = new Point(30, 40);
Size s1 = new Size(300, 400);
Rectangle r1 = new Rectangle(p1, s1); //绘制临时矩形
g.DrawRectangle(p, r1);
g.Dispose();
}
private void button2_Click(object sender, EventArgs e)
{
isDrawyongjiu = true; //利用参数修改值,并放入到Paint事件中,就会形成永久绘图
//第一次绘制
Graphics g = this.CreateGraphics();
Pen p = new Pen(Color.Blue, 1);
Point p1 = new Point(50, 45);
Size s1 = new Size(200, 100);
Rectangle r1 = new Rectangle(p1, s1);
g.DrawRectangle(p, r1);
g.Dispose();
}
//永久型绘制
private void Form1_Paint(object sender, PaintEventArgs e)
{
//之后的每次绘制
if (isDrawyongjiu == true)
{
//获取g对象
Graphics g = e.Graphics;
Pen p = new Pen(Color.Blue, 1);
Point p1 = new Point(50, 45);
Size s1 = new Size(200, 100);
Rectangle r1 = new Rectangle(p1, s1);
g.DrawRectangle(p, r1);
g.Dispose();
}
}
图像类
image类是所有图像的抽象基类,派生类有BitMap和MetaFile
重要方法
- FromFile——根据文件的数据创建图像
- Save——将图像存入到文件当中
Bitmap bm = new Bitmap(@ "C:tempimage.jpg"); g.DrawImage(bmp,new Point(50,50));
private void button3_Click(object sender, EventArgs e)
{
// 创建项目的debug里面进行绘制
Bitmap image1 = new Bitmap(Application.StartupPath+@"yaomin.bmp");
Graphics g = Graphics.FromImage(image1); //获得一个副本类似的对象,因为本身不能直接对着图像进行修改
Pen p = new Pen(Color.Blue, 1);
Point p1 = new Point(50, 45);
Size s1 = new Size(200, 100);
Rectangle r1 = new Rectangle(p1, s1);
g.DrawRectangle(p, r1);
image1.Save(Application.StartupPath + @"yaomin1.bmp"); //两个名字要不一样,因为一样会报错(某人问过)
g.Dispose();
}
Pen类
在.NET框架中绘制图形需要用到画笔,就需要Pen类进行表示
Dispose()方法进行释放对象所占用的资源
Pen redPen = new Pen(Color.Red,1);Brush类
在.NET框架绘制图形需要用到的是画刷,是一个填充区域的工具——Brush是抽象类
常用的派生类
- SolidBrush类——单色画刷
- TextureBrush类——一个图像填充内部区域的刷子
- LinearGradientBrush——线性渐变类
- ……
颜色的表示
注意:Color没有构造函数,只能通过静态的生成方式返回引用对象
Color c2 =Color.FromArgb(255,0,127); //通过 RGB进行颜色地选取Font类
窗体或控件对象包含着一个Font属性
Font类表示字体——名称、大小、样式属性
字体的样式属性用FontStyle枚举来表示
- Bold——表示粗体文字
- Italic——表示粗体文字
- ……
Font具有的属性都是可读的性质,因为字体在创建的时候就被固定了
创建字体的操作
字体家族+字体大小+样式属性+另外现有的字体
Font fnt = new Font("Verdana",25,FontStyle.Bold);
坐标变换
坐标类型
- 全局坐标(相对坐标)(无单位)
- 页面坐标(有单位)
- 设备坐标(有单位)
全局坐标——一般情况下使用的
页面坐标——绘制页面使用的虚拟坐标,单位例如厘米,英寸等等
设备坐标——输出到设备实际使用的坐标
G 常见属性
- PageScale 比例尺
- PageUnit 单位
- ScaleTransform 比例
- TranslateTransform 平移
- RotateTransform 旋转——顺时针为正方向
注意:修改的不是图像的大小,而是坐标系,坐标系的缩小和放大等等
private void button1_Click_1(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.FromArgb(122, 222, 9));
Point p1 = new Point(20, 20);
Point p2 = new Point(40, 40);
g.DrawLine(pen, p1, p2);
}
private void button2_Click(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
//修改比例尺,数字越大,放大的比例越大
g.PageScale = 10f;
//修改单位,方法可能麻烦了一些,但是思路是这样的,有好方法私信一下 o(* ̄▽ ̄*)o
if (comboBox2.SelectedIndex == 0)
{
g.PageUnit = GraphicsUnit.Millimeter; //毫米
}
if (comboBox2.SelectedIndex == 1)
{
g.PageUnit = GraphicsUnit.Pixel; //像素
}
if (comboBox2.SelectedIndex == 2)
{
g.PageUnit = GraphicsUnit.Inch; //英寸
}
if (comboBox2.SelectedIndex == 3)
{
g.PageUnit = GraphicsUnit.Point;
}
Pen pen = new Pen(Color.FromArgb(122, 222, 9));
Point p1 = new Point(20, 20);
Point p2 = new Point(40, 40);
g.DrawLine(pen, p1, p2);
}
private void button3_Click(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
g.TranslateTransform(10, 10); //平移
g.RotateTransform(45F); //旋转坐标系
g.ScaleTransform(1.2f, 1.2f); //比例放大
Pen pen = new Pen(Color.FromArgb(122, 42, 9));
Point p1 = new Point(20, 20);
Point p2 = new Point(40, 40);
g.DrawLine(pen, p1, p2);
}
背景色和前景色
BackgroundColor/BackColor——设置背景色 (不同的单元有不同的属性)
ForegroundColor/ForeColor——设置前景色
如何获取控制台颜色
//二者都是静态的方法,可以直接获取
Console.BackgroundColor
Console.ForegroundColor
//控件颜色的获取
private void btnBackColor_Click(object sender, EventArgs e)
{
//调用ShowDialog方法显示用于选择颜色的窗口
if (this.colorDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
//如果单击“确认键",showDialog方法返回DialogResult.OK
this.label1.BackColor = this.colorDialog1.Color;//设置label1的背景颜色
}
}
private void btnForeColor_Click(object sender, EventArgs e)
{
if (this.colorDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
this.label1.ForeColor = this.colorDialog1.Color;//设置label1的前景颜色
}
}
第六章 文件管理
System.IO命名空间——允许读写文件和数据流类型
类
-
Directory——操纵文件夹——静态方法
-
Directoryinfo——操纵文件夹
-
File——操纵文件
-
FileInfo
-
Path——目录信息操作——操作路径
枚举
- FileMode——指定操作文件的打开方式
- Append
- Create
- CreateNew
- Open
- ……
- FileShare
- None
- Read
- Write
- ReadWrite
- ……
二者功能类似
区别
-
Directory是静态类,方法均为静态方法,方法通过类名进行访问
-
DirectoryInfo类方法全部都是实例方法
-
对一个文件夹进行大量的操作使用DirectoryInfo,其余用Directory
Directory类-方法
- CreateDirectory——创建指令目录的所有目录
- Exist——判断是否存在
- Move——将文件或者目录及其内容移到新的位置
- ……
File和FileInfo类
二者功能相似
区别
- File是静态类,方法均为静态方法
- FileInfo是实例类,大部分是实例方法
- 对一个文件进行操作的时候,采取的是FileInfo
File类的方法
- Copy——将现有的文本复制到新文件
//源文件路径,目标路径,是否替换
File.Copy("C:\1.txt","C:\2.txt",true);
- Create——在指定路径下创建文件
- Open——打开指定路径的FileSream
- OpenWrite——打开文本以进行写入,返回的是文件流FileStream对象
- OpenRead——打开文本以进行读取,返回文件流FileStream对象
- OpenText——打开文本以进行读取,返回文本流StreamReader对象
- AppendText——打开文本进行写入,返回文件流StreamReader对象
Path类对包含文件或目标路径信息的string实例进行操作
- GetDirectoryName——返回指定路径字符串的目录信息
- GetExtension——返回指定路径的字符串的文件名和扩展名
- GetFileName——返回指定路径字符串的文件名和扩展名
- GetFullPath——返回绝对路径
- ……
private void button1_Click(object sender, EventArgs e)
{
// 默认地址在创建文件的binDebug
String path = Application.StartupPath;
richTextBox1.Text = path;
//获取内容
String direcName = textBox1.Text;
Directory.CreateDirectory(path+"\"+direcName);
}
private void button2_Click(object sender, EventArgs e)
{
String path = Application.StartupPath;
richTextBox1.Text = path;
String direcName = textBox1.Text;
for (int i=1;i<=10;i++)
{
Directory.CreateDirectory(path + "\" + direcName+"\"+i);
}
}
private void button3_Click(object sender, EventArgs e)
{
String path = Application.StartupPath;
richTextBox1.Text = path;
String direcName = textBox1.Text;
Directory.Move(path + "\" + direcName, path + "\" + "abc");
}
private void button4_Click(object sender, EventArgs e)
{
String path = Application.StartupPath;
for (int i = 5; i <= 10; i++)
{
Directory.Delete(path + "\" + "abc"+"\"+i);
}
}
private void button5_Click(object sender, EventArgs e)
{
String path = Application.StartupPath +"\" + "abc";
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] di4 = di.GetDirectories(); //返回目录夹下的文本列表
for (int i = 0; i < di4.Length; i++)
{
File.Create(di4[i].FullName + "\" + "12班.地信20级12班");
}
}
文件流-读写
支持的文本类型操作——文本内容、二进制文件
操作步骤
- 创建一个文件流
//初始化文件流
FileStream file = File.Open("D:\temp",FileMode.Open);
- 创建相对应的读写器
//文件文本写入器 StreamWriter sw = new StreamWriter(file); //文件文本读写器 StreamReader sr = new StreamReader(file); //二进制读写器 BinaryReader br = new BinaryReader(file); //二进制写入器 BinaryWriter bw = new BinaryWriter(file);
- 执行读写操作
- 关闭读写器
sw.Close();
- 关闭文件流
file.Close();
private void 文本读入器_Click(object sender, EventArgs e)
{
string path = Application.StartupPath;
FileStream fs = File.Open(path+"\1.txt",FileMode.Open);
//创建该文件流的读写器
StreamReader sr = new StreamReader(fs);
//执行读写操作
string s;
while((s=sr.ReadLine())!=null)
{
richTextBox1.AppendText(s+"n");
}
//关闭读写器
sr.Close();
//关闭文件流
fs.Close();
}
private void 文本写入器_Click(object sender, EventArgs e)
{
string path = Application.StartupPath;
FileStream fs = File.Open(path + "\2.txt", FileMode.CreateNew);
StreamWriter sr = new StreamWriter(fs);
sr.Write(richTextBox1.Text);
sr.Close();
fs.Close();
}
private void 二进制读入_Click(object sender, EventArgs e)
{
string path = Application.StartupPath;
FileStream fs = File.Open(path + "\3.yjj", FileMode.Open);
BinaryReader sr = new BinaryReader(fs);
int x=sr.ReadInt32();
string y = sr.ReadString();
bool z = sr.ReadBoolean();
richTextBox1.Text = x.ToString() + y + z.ToString();
sr.Close();
fs.Close();
}
private void 二进制写入_Click(object sender, EventArgs e)
{
string path = Application.StartupPath;
FileStream fs = File.Open(path + "\3.yjj", FileMode.CreateNew);
BinaryWriter sr = new BinaryWriter(fs);
sr.Write((int)7);
sr.Write((string)"sss");
sr.Write((bool)true);
sr.Close();
fs.Close();
}
private void 保存操作_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
DialogResult dr= sfd.ShowDialog();
if(dr==DialogResult.OK)
{
string path = Application.StartupPath;
FileStream fs = File.Open(sfd.FileName, FileMode.CreateNew);
StreamWriter sr = new StreamWriter(fs);
sr.Write(richTextBox1.Text);
sr.Close();
fs.Close();
}
}
第七章 数据库
C#中访问数据库的技术称为ADO.NET技术
组成部分是数据提供程序、数据集(DataSet)
数据集——内存中的一个数据库,它与数据源断开连接
数据提供程序分为SQL Server、Oracle、OLE DB、ODBC
四个包含对象- DataAdapter——大货车——拉着数据库到数据集
- Connection——马路——与数据源的连接
- Command——对数据源的命令
- DataReader——飞机
Command对象执行的操作
ExecuteReader——将查询结果放入到datareader对象里面
ExecuteScale——返回单一值
ExecuteNonQuery——执行不返回结果集的查询
数据集
DataSet——表示数据在客户机内存的缓存
DataTable——表示DataSet的一个表
DataRelation——描述表之间的关系
DataAdapter的读取数据步骤- 创建连接对象(SQLConnection)
- 创建适配对象(DataAdapter)
- 执行装填(.fill)
- 关闭对象
连接字符串
string path = @"Data Source=.; Initial Catalog =Training; Intergrated Security = True";
- Data Source指定数据库服务器名称
- Initial CataLog指定数据库名称
- Integrated Security是否使用Windows验证用户登录
1.创建连接对象(SQLConnection)
2.创建命令对象(Command),书写自己的sql语句
3.执行命令(.ExecuteReader())
4.关闭对象
实例演示private void button1_Click(object sender, EventArgs e)
{
string conn = "data source=.;initial catalog=django;user id = root;password=`1qaz`2wsx";
//创建链接对象
SqlConnection sc = new SqlConnection(conn);
sc.Open();
//查询命令
SqlCommand sco= sc.CreateCommand();
sco.CommandText = "SELECT * FROM student"; //他的命令不需要是数据库command
//执行命令
SqlDataReader sdr= sco.ExecuteReader(); //一个一个读,没有存入到数据集上
while(sdr.Read())
{
richTextBox1.AppendText(sdr[0].ToString()+" ");
richTextBox1.AppendText(sdr[1].ToString() + " ");
richTextBox1.AppendText(sdr[2].ToString() + " ");
richTextBox1.AppendText(sdr[3].ToString() + " ");
richTextBox1.AppendText(sdr[4].ToString() + " ");
richTextBox1.AppendText("n");
}
sdr.Close();
sc.Close();
//
}
private void button2_Click(object sender, EventArgs e)
{
string conn = "data source=.;initial catalog=地信20级产业;user id = sa;password=`1qaz`2wsx";
//创建链接对象
SqlConnection sc = new SqlConnection(conn);
sc.Open();
//大货车型
string commandText = "SELECt * FROM student";
SqlDataAdapter sda = new SqlDataAdapter(commandText, conn);
//执行命令
DataSet ds = new DataSet(); //放到数据集上
sda.Fill(ds);
sda.Dispose();
//绑定
dataGridView1.DataSource = ds.Tables[0];
}
private void button3_Click(object sender, EventArgs e)
{
string conn = "data source=.;initial catalog=地信20级产业;user id = sa;password=`1qaz`2wsx";
//创建链接对象
SqlConnection sc = new SqlConnection(conn);
sc.Open();
//删除命令
SqlCommand sco = sc.CreateCommand();
//string sql= "SELECt 姓名,年龄 FROM student WHERe 姓名='" + textBox1.Text + "'"; //动态查询的方法
sco.CommandText = "DELETe FROM student WHERe xuehao='2020002'";
//执行命令
int i= sco.ExecuteNonQuery();
MessageBox.Show(i.ToString());
//sdr.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: 这行代码将数据加载到表“地信20级产业DataSet.student”中。您可以根据需要移动或删除它。
this.studentTableAdapter.Fill(this.地信20级产业DataSet.student);
}
private void fillByToolStripButton_Click(object sender, EventArgs e)
{
try
{
this.studentTableAdapter.FillBy(this.地信20级产业DataSet.student);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
private void fillBy1ToolStripButton_Click(object sender, EventArgs e)
{
try
{
this.studentTableAdapter.FillBy1(this.地信20级产业DataSet.student);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
private void button4_Click(object sender, EventArgs e)
{
string conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data source="+Application.StartupPath+ "\全国省市县Access数据库(完整版).mdb";
//创建链接对象
OleDbConnection sc = new OleDbConnection(conn);
sc.Open();
//查询命令
OleDbCommand sco = sc.CreateCommand();
sco.CommandText = "SELECt * FROM LinkCN";
//执行命令
OleDbDataReader sdr = sco.ExecuteReader();
while (sdr.Read())
{
richTextBox2.AppendText(sdr[0].ToString() + " ");
richTextBox2.AppendText(sdr[1].ToString() + " ");
richTextBox2.AppendText(sdr[2].ToString() + " ");
richTextBox2.AppendText(sdr[3].ToString() + " ");
//richTextBox1.AppendText(sdr[4].ToString() + " ");
richTextBox2.AppendText("n");
}
sdr.Close();
sc.Close();
}
private void button5_Click(object sender, EventArgs e)
{
string conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data source=" + Application.StartupPath + "\全国省市县Access数据库(完整版).mdb";
//创建链接对象
OleDbConnection sc = new OleDbConnection(conn);
sc.Open();
//查询命令
string commandText = "SELECt * FROM LinkCN";
OleDbDataAdapter sda = new OleDbDataAdapter(commandText, conn);
//执行命令
DataSet ds = new DataSet();
sda.Fill(ds);
sda.Dispose();
//绑定
dataGridView3.DataSource = ds.Tables[0];
}
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
comboBox1.SelectedText = "";
//第几行
int rowi = e.RowIndex;
textBox1.Text = dataGridView1.Rows[rowi].Cells[1].Value.ToString();
textBox2.Text = dataGridView1.Rows[rowi].Cells[2].Value.ToString();
comboBox1.SelectedText = dataGridView1.Rows[rowi].Cells[3].Value.ToString();
textBox3.Text = dataGridView1.Rows[rowi].Cells[4].Value.ToString();
}
private void button6_Click(object sender, EventArgs e)
{
string conn = "data source=.;initial catalog=地信20级产业;user id = sa;password=`1qaz`2wsx";
//创建链接对象
SqlConnection sc = new SqlConnection(conn);
sc.Open();
//删除命令
SqlCommand sco = sc.CreateCommand();
//UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing' WHERe LastName = 'Wilson'
sco.CommandText = "UPDATE student SET name='"+textBox2.Text+"',age='"+comboBox1.Text+"' WHERe xuehao='"+textBox1.Text+"'";
//执行命令
int i = sco.ExecuteNonQuery();
MessageBox.Show(i.ToString());
//sdr.Close();
}
private void button7_Click(object sender, EventArgs e)
{
string conn = "data source=.;initial catalog=地信20级产业;user id = sa;password=`1qaz`2wsx";
//创建链接对象
SqlConnection sc = new SqlConnection(conn);
sc.Open();
//删除命令
SqlCommand sco = sc.CreateCommand();
//UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing' WHERe LastName = 'Wilson'
sco.CommandText = "DELETE FROM student WHERe xuehao='" + textBox1.Text + "'";
//执行命令
DialogResult dr = MessageBox.Show("确定删除吗?", "提示", MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
int i = sco.ExecuteNonQuery();
MessageBox.Show(i.ToString());
}
//sdr.Close();
}
都看到最后了,求给博主一个三连把,你的三连,是我最大的动力



