您的位置:首页 > 理论基础 > 计算机网络

C#网络应用编程基础练习题与答案(转载)

2008-10-06 23:24 423 查看
C#网络应用编程基础练习题与答案

1. C/S结构模式与B/S结构模式的主要区别是什么?

  【解答】

  首先,在系统的性能方面。只要拥有可上网的浏览器,就可以使用B/S系统。不过,B/S结构的客户端只能完成浏览、查询、数据输入等简单功能,绝大部分工作要由服务器承担,这就对服务器提出了很高的要求,无形中增加了用户在这一方面的投入。采用C/S结构时,客户端和服务器都承担部分工作,有效利用了客户端和服务器端的资源,使用户不必在硬件上有更多的投入。另外,浏览器页面不便于修改,这为用户定制自己的文件时带来了不便,比如用户想自定义一个报表,用B/S结构的系统就比较难完成。

  其次,在系统的开发方面,C/S结构的开发对开发者提出了较高的要求,整个开发过程比较复杂。与B/S结构相比,C/S技术的历史更为“悠久”,从技术成熟度和开发人员普遍掌握的水平来看更为成熟。

  第三,系统升级方面。C/S结构中若有某一模块发生改变,可能要关联到其它模块的变动,使系统升级的成本较大;而B/S结构在开发、维护阶段几乎所有的工作都集中在服务器端,只需更新服务器端的软件就可以了。如果系统升级比较频繁,那么B/S架构的产品就具有维护工作量少的优势。

  第四,安全性方面。在安全性上,B/S结构则略显不足,毕竟现在网络安全系数不高,只要拥有密码,任何人都可以进入到用户的系统中;而C/S结构由于需要特定的客户端软件,并且一般来说都要对客户端加密,甚至可以限定只有某一台计算机可以使用这个客户端,因而对安全性有更多的保障。

  2. 可以用C#编写哪些类型的应用程序?

  【解答】

  1) 控制台应用程序。

  2) Windows应用程序。

  3) 水晶报表应用程序。

  4) ASP.NET Web应用程序。

  5) ASP.NET Web服务应用程序。

  6) ASP.NET 水晶报表Web应用程序。

  7) 智能设备应用程序。

  3. 什么是命名空间?命名空间和类库的关系是什么?

  【解答】

  1) 名称空间是对类的一种逻辑上的分组,即将类按照某种关系或联系划分到不同的名称空间下。

  2) 名称空间又可以包含其它的名称空间,例如System.Windows.Forms,是指System名称空间下有Windows名称空间,Windows名称空间下有Forms名称空间。

  3) 所有类库都在规定的名称空间下。

1. C#支持的数据类型有那些?与C++相比有哪些特点?

  【解答】

  C#支持的数据类型有:

  (1) 值类型

  包括:简单类型、结构类型、枚举类型。其中,简单类型又分为:整型、布尔型、字符型、浮点型、小数型。

  (2) 引用类型

  包括:对象类型、类类型、接口、元数据、字符串类型、数组。

  与C++相比,C#的主要特点有:

  1) C#语言自C/C++演变而来。但是,它是完全按照面向对象的思想来设计的,并保证了类型的安全性。

  2) C#简化了C++在类、名称空间、方法重载和异常处理等方面的使用。摒弃了C++的复杂性,使它更易用、更少出错。

  3) C#减少了C++的一些特性,不再有宏、多重继承。特别对企业开发者来说,上述功能只会产生更多的麻烦而不是效益。

  4) C#采用严格的类型安全、版本控制、垃圾收集(garbage collect)等等。所有的这些功能的目标都是瞄准了开发面向组件的软件开发。

  5) C#中不再有“::”、“.”、和“->”操作符,仅使用单个操作符“.”。

  6) C#使用统一的类型系统,摒弃了C++多变的类型系统。

  7) 在C#中,不能在类的外部定义全局函数、变量或者是常量等。所有的东西都必须封装在类中,包括实例成员或静态成员。从而使C#代码更加易读且有助于减少潜在的命名冲突。

  8) 在C#中,不能使用没有初始化的变量。从而避免了由于使用不经初始化的变量而导致的计算结果错误。

  2. C#语言中,值类型和引用类型有何不同?

  【解答】

  值类型和引用类型的区别在于,值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的地址,即对象的引用。

  值类型变量直接把变量的值保存在堆栈中,引用类型的变量把实际数据的地址保存在堆栈中,而实际数据则保存在堆中。注意,堆和堆栈是两个不同的概念,在内存中的存储位置也不相同,堆一般用于存储可变长度的数据,如字符串类型;而堆栈则用于存储固定长度的数据,如整型类型的数据int(每个int变量占用四个字节)。由数据存储的位置可以得知,当把一个值变量赋给另一个值变量时,会在堆栈中保存两个完全相同的值;而把一个引用变量赋给另一个引用变量,则会在堆栈中保存对同一个堆位置的两个引用,即在堆栈中保存的是同一个堆的地址。在进行数据操作时,对于值类型,由于每个变量都有自己的值,因此对一个变量的操作不会影响到其它变量;对于引用类型的变量,对一个变量的数据进行操作就是对这个变量在堆中的数据进行操作,如果两个引用类型的变量引用同一个对象,实际含义就是它们在堆栈中保存的堆的地址相同,因此对一个变量的操作就会影响到引用同一个对象的另一个变量。

  3. 结构和类的区别是什么?

  【解答】

  1) 结构是一个值类型,保存在栈上,而类是一个引用类型,保存在受管制的堆上。

  2) 对结构中的数据进行操作比对类或对象中的数据进行操作速度要快。

  3) 一般用结构存储多种类型的数据,当创建一个很多类或对象共用的小型对象时,使用结构效率更高。

  4. C#中的数组类型有何特点?

  【解答】

  1) 数组一般用于存储同一种类型的数据,包括Object类型。

  2) 数组是一种引用类型,而不是值类型。

  3) C#中除了可以有一维数组、多维数组外,还有交错型数组。

  5. C#中不同整型之间进行转换的原则是什么?

  【解答】

  在整型之间进行转换时,小范围类型可以隐式转换为大范围类型,但大范围类型转换为小范围类型时需要使用显式转换。

  6. 简述装箱和拆箱的过程。

  【解答】

  装箱是将值类型隐式地转换为object类型或者转换为由该值类型实现了的接口类型。装箱一个数值会为其分配一个对象实例,并把该数值拷贝到新对象中。拆箱是显式地把object类型转换成值类型,或者把值类型实现了的接口类型转换成该值类型。

  7. 下列写法哪些是错误的?为什么?

  1) if (nMyValue1=5) i=1;

  2) if(nMyValue2==1)i=1;

  3) int[] myInt={1,2,3};

  foreach(int test in myInt)

  {

  test++;

  Console.WriteLine(temp);

  }

  4) int[] myInt1={1,2,3};

  foreach(int test in myInt1)

  {

  Console>WriteLine(test);

  }

  【解答】

  1) 错误。if中的条件表达式结果不是布尔型。

  2) 正确。

  3) 错误一:temp没有定义。

  错误二:在foreach块内,test作为枚举成员是只读的,不能使用test++修改其值。

  4) 错误。Console后应该是点,而不应该是大于号。

  8. 错误和异常有什么区别,为什么要进行异常处理,用于异常处理的语句有哪些?

  【解答】

  错误是指在执行代码过程中发生的事件,它中断或干扰代码的正常流程并创建异常对象。当错误中断流程时,该程序将尝试寻找异常处理程序(一段告诉程序如何对错误做出响应的代码),以帮助程序恢复流程。换句话说,错误是一个事件,而异常是该事件创建的对象。

  当使用短语“产生异常”时,表示存在问题的方法发生错误,并创建异常对象(包含该错误的信息及发生的时间和位置)来响应该错误。导致出现错误和随后异常的因素包括用户错误、资源失败和编程逻辑失败。这些错误与代码实现特定任务的方法有关,而与该任务的目的无关。

  如果不进行异常处理,即不对错误做出响应,程序的健壮性就会大打折扣,甚至无法保证正常运行,所以必须要进行异常处理。

  用于异常处理的语句有:try-catch语句、try-catch-finally语句、throw语句。

  9. 编写一个控制台应用程序,输出1到5的平方值,要求:

  1) 用for语句实现。

  2) 用while语句实现。

  3) 用do-while语句实现。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.Text;

  namespace outputSquareValue

  {

  class Program

  {

  static void Main()

  {

  //用for语句实现

  for (int i = 1; i <= 5; i++)

  {

  Console.WriteLine("{0}的平方值为{1}", i, i * i);

  }

  //用while语句实现

  int j = 0;

  while (j++ < 5)

  {

  Console.WriteLine("{0}的平方值为{1}", j, j * j);

  }

  //用do-while语句实现

  int k = 1;

  do

  {

  Console.WriteLine("{0}的平方值为{1}", k, k * k);

  } while (k++ < 5);

  Console.ReadLine();

  }

  }

  }

  10. 编写一个控制台应用程序,要求用户输入5个大写字母,如果用户输入的信息不满足要求,提示帮助信息并要求重新输入。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.Text;

  namespace inputCapitalLetter

  {

  class Program

  {

  static void Main()

  {

  bool ok = false;

  while (ok == false)

  {

  Console.Write("请输入5个大写字母:");

  string str = Console.ReadLine();

  if (str.Length != 5)

  {

  Console.WriteLine("你输入的字符个数不是5个,请重新输入。");

  }

  else

  {

  ok = true;

  for (int i = 0; i < 5; i++)

  {

  char c = str[i];

  if (c < 'A' || c > 'Z')

  {

  Console.WriteLine("第{0}个字符“{1}”不是大写字母,请重新输入。", i + 1, c);

  ok = false;

  break;

  }

  }

  }

  }

  }

  }

  }

  11. 编写一个控制台应用程序,要求完成下列功能。

  1) 接收一个整数n。

  2) 如果接收的值n为正数,输出1到n间的全部整数。

  3) 如果接收的值为负值,用break或者return退出程序。

  4) 转到(1)继续接收下一个整数。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.Text;

  namespace testOutput

  {

  class Program

  {

  static void Main()

  {

  while (true)

  {

  Console.Write("请输入一个整数(负值结束):");

  string str = Console.ReadLine();

  try

  {

  int i = Int32.Parse(str);

  if (i < 0) break;

  for (int j = 1; j <= i; j++) Console.WriteLine(j);

  }

  catch

  {

  Console.WriteLine("你输入的不是数字或超出整数的表示范围,请重新输入");

  }

  }

  }

  }

  }

  12. 编写一个控制台应用程序,求1000之内的所有“完数”。所谓“完数”是指一个数恰好等于它的所有因子之和。例如,6是完数,因为6=1+2+3。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.Text;

  namespace completeNumber

  {

  class Program

  {

  static void Main(string[] args)

  {

  for (int i = 2; i <= 1000; i++)

  {

  int s = 1;

  string str = "1";

  for (int j = 2; j <= (int)Math.Sqrt(i); j++)

  {

  if (j * (i / j) == i)

  {

  if (j != i / j)

  {

  s += j + i / j;

  str += string.Format("+{0}+{1}", j, i / j);

  }

  else

  {

  s += j;

  str += string.Format("+{0}", j);

  }

  }

  }

  if (s == i) Console.WriteLine("{0}={1}", i, str);

  }

  Console.ReadLine();

  }

  }

  }

C#网络应用编程基础练习题与答案

1. 编写一个控制台应用程序,完成下列功能。

  1) 创建一个类,用无参数的构造函数输出该类的类名。

  2) 增加一个重载的构造函数,带有一个string类型的参数,在此构造函数中将传递的字符串打印出来。

  3) 在Main方法中创建属于这个类的一个对象,不传递参数。

  4) 在Main方法中创建属于这个类的另一个对象,传递一个字符串“This is a string.”。

  5) 在Main方法中声明类型为这个类的一个具有5个对象的数组,但不要实际创建分配到数组里的对象。

  6) 写出运行程序应该输出的结果。

  【解答】

  using System;

  class Test1

  {

  public Test1()

  {

  Console.WriteLine(this);

  }

  public Test1(string str)

  {

  Console.WriteLine(str);

  }

  public static void Main()

  {

  Test1 t1 = new Test1();

  Test1 t2 = new Test1("This is a string.");

  Test1[] t3 = new Test1[5];

  }

  }

  输出结果:

  Test1

  This is a string.

  2. 编写一个控制台应用程序,定义一个类MyClass,类中包含有public、private以及protected数据成员及方法。然后定义一个从MyClass类继承的类MyMain,将Main方法放在MyMain中,在Main方法中创建MyClass类的一个对象,并分别访问类中的数据成员及方法。要求注明在试图访问所有类成员时哪些语句会产生编译错误。

  【解答】

  using System;

  class MyClass

  {

  public int i;

  private int j;

  protected int k;

  public void method1()

  {

  Console.WriteLine("public method.");

  }

  private void method2()

  {

  Console.WriteLine("private method.");

  }

  protected void method3()

  {

  Console.WriteLine("protected method.");

  }

  }

  class MyMain : MyClass

  {

  public static void Main()

  {

  MyClass t = new MyClass();

  Console.WriteLine("i={0}", t.i);

  Console.WriteLine("j={0}", t.j); //会出现编译错误,私有成员不允许在其它类中访问

  Console.WriteLine("k={0}", t.k); //会出现编译错误,应该创建MyMain的对象,然

  //后通过MyMain的对象访问

  t.method1();

  t.method2(); //会出现编译错误,私有的方法不允许在其它类中调用

  t.method3(); //会出现编译错误,应该创建MyMain的对象,然后通过MyMain的

  //对象调用该方法

  }

  }

  3. 创建一个类包含有protected数据。在相同的文件里创建第二个类,用一个方法操纵第一个类里的protected数据。

  【解答】

  using System;

  class Class1

  {

  protected int i = 5;

  protected void MyMethod()

  {

  Console.WriteLine("protected method.");

  }

  }

  class Class2 : Class1

  {

  private void NewMethod()

  {

  Console.WriteLine(this.i);

  this.i += 10;

  Console.WriteLine(this.i);

  }

  public static void Main()

  {

  Class2 t = new Class2();

  t.NewMethod();

  }

  }

  4. 分别写出下列语句执行的结果。

  1) Console.WriteLine("{0}--{0:p}good",12.34F);

  2) Console.WriteLine("{0}--{0:####}good",0);

  3) Console.WriteLine("{0}--{0:00000}good",456);

  【解答】

  12.34--1,234.00%good

  0--good

  456--00456good

  5. 编写一个控制台应用程序,计算

  要求精度为10-8。

  【解答】

  using System;

  class Test5

  {

  public static void Main()

  {

  int n = 50;

  double x = 3;

  double s = 0;

  double a = 1;

  for (int i = 1; i <= n; i++)

  {

  a *= i;

  s += Math.Pow(-1, i + 1) * Math.Pow(x, i) / a;

  }

  Console.WriteLine("n={0},s={1:0.00000000}", n, s);

  }

  }

  6. 编写一个控制台应用程序,接收一个长度大于3的字符串,完成下列功能

  1) 输出字符串的长度。

  2) 输出字符串中第一个出现字母a的位置。

  3) 在字符串的第3个字符后面插入子串“hello”,输出新字符串。

  4) 将字符串“hello”替换为“me”,输出新字符串。

  5) 以字符“m”为分隔符,将字符串分离,并输出分离后的字符串。

  【解答】

  using System;

  class Test6

  {

  public static void Main()

  {

  string str = "";

  while (str.Length <= 3)

  {

  Console.Write("请输入一个长度大于3的字符串:");

  str = Console.ReadLine();

  }

  //(1)

  Console.WriteLine("字符串的长度为:{0}", str.Length);

  //(2)

  int i = str.IndexOf('a');

  if (i > -1)

  {

  Console.WriteLine("第一个出现字母a的位置是:{0}", i);

  }

  else

  {

  Console.WriteLine("字符串中不包含字母a。");

  }

  //(3)

  string str1 = str.Insert(3, "hello"); //在第3个(初始序号为)字符前插入hello

  Console.WriteLine("插入hello后的结果为:{0}", str1);

  //(4)

  string str2 = str1.Replace("hello", "me");

  Console.WriteLine("将hello替换为me后的结果为:{0}", str2);

  //(5)

  string[] arr = str2.Split('m');

  Console.WriteLine("以m为分隔符分离后的字符串有:");

  for (int j = 0; j < arr.Length; j++)

  {

  Console.WriteLine(arr[j]);

  }

  }

  }

1. 与结构化编程方法相比,面向对象编程有哪些优点?

  【解答】

  (1) 以过程为中心和对象为中心的比较

  结构化编程方法是以过程为中心的,当面对一个问题时,该方法侧重于问题解决过程的层次结构。面向对象的分析和设计方法侧重于对象。对象具有特定的行为和属性,行为和属性决定了对象与其他对象的交互作用方式,以及对象本身的行为方式。

  (2) 公开数据和隐藏数据的比较

  结构化编程方法对数据和过程仅仅进行简单的包装,这些数据和过程是公开的,或者说程序中的其他代码可以访问这些数据和过程。面向对象的实现隐藏了特定的数据,并且只把对象的特定行为公开给用户。实现这些特定行为的代码对用户来说是不可见的,用户只能访问这些公开的行为。

  (3) 单一单元和标准单元的比较

  结构化编程方法是基于单一代码单元的。面向对象的编程方法允许对象是独立的。

  (4) 一次性使用和可重用的比较

  根据不同的实现,结构化过程可能无法重用。而面向对象的方法,对象是一个模块单元。具有完备的实体,因此可以具有高度的可重用性。

  (5) 有序算法和无序算法的比较

  结构化编程方法所开发的程序,其结构往往是线性的(或者说是自顶向下的)。而面向对象的应用程序是一种基于消息或者事件驱动的程序类型。每个对象都可以向其他对象发送消息。Windows操作系统就是这样的程序。

  2. 简要回答下列问题。

  1) 举例说明new关键字可用于那些方面?

  2) sealed关键字的作用是什么?什么情况下需要使用sealed关键字?

  3) 哪些关键字可以用于版本控制?

  【解答】

  1) 在C#中,new关键字可用作运算符或修饰符。作为运算符用于在堆上创建对象和调用构造函数。作为修饰符用于隐藏基类成员的继承成员。

  2) 在类声明中使用sealed修饰符可防止其它类继承此类。在方法声明中使用sealed修饰符可防止扩充类重写此方法。

  sealed修饰符主要用于防止非有意的派生,但是它还能促使某些运行时优化。具体说来,由于密封类永远不会有任何派生类,所以对密封类的实例的虚拟函数成员的调用可以转换为非虚拟调用来处理。

  3) override关键字和new关键字均可用于版本控制。

  在C#中,默认情况下方法不是虚拟的。若要使方法成为虚拟方法,必须在基类的方法声明中使用virtual修饰符。然后,派生类可以使用override关键字重写基类中的虚拟方法,或使用new关键字隐藏基类中的虚拟方法。如果override关键字和new关键字均未指定,编译器将发出警告,并且派生类中的方法将隐藏基类中的方法。

  3. 简要回答抽象类和接口的主要区别。

  【解答】

  抽象类和接口的一个主要差别是:类可以实现多个接口,但仅能从一个抽象类或任何其它类型的类继承。

  4. 使用委托的优点是什么?委托和事件有什么区别和联系?

  【解答】

  C#中的委托类似于C或C++中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。

  C#中的“事件”是当对象发生某些事情时,类向该类的客户提供通知的一种方法。事件最常见的用途是用于图形用户界面;通常,表示界面中的控件的类具有一些事件,当用户对控件进行某些操作(如单击某个按钮)时,将通知这些事件。

  使用委托来声明事件。委托对象封装一个方法,以便可以匿名调用该方法。事件是类允许客户为其提供方法(事件发生时应调用这些方法)的委托的一种方法。事件发生时,将调用其客户提供给它的委托。

  5. 编写一个控制台应用程序,完成下列功能,并回答提出的问题。

  1) 创建一个类A,在构造函数中输出“A”,再创建一个类B,在构造函数中输出“B”。

  2) 从A继承一个名为C的新类,并在C内创建一个成员B。不要为C创建构造函数。

  3) 在Main方法中创建类C的一个对象,写出运行程序后输出的结果。

  4) 如果在C中也创建一个构造函数输出“C”,整个程序运行的结果又是什么?

  【解答】

  using System;

  public class A

  {

  public A()

  {

  Console.WriteLine("A");

  }

  }

  public class B

  {

  public B()

  {

  Console.WriteLine("B");

  }

  }

  public class C : A

  {

  B newb = new B();

  }

  class MainClass

  {

  public static void Main()

  {

  C newc = new C();

  Console.ReadLine();

  }

  }

  输出结果:

  B

  A

  如果在C中也创建一个构造函数输出“C”,即添加:

  public C()

  {

  Console.WriteLine("C");

  }

  则整个程序运行的结果为:

  B

  A

  C

  6. 编写一个控制台应用程序,完成下列功能,并写出运行程序后输出的结果。

  1) 创建一个类A,在A中编写一个可以被重写的带int类型参数的方法MyMethod,

  并在该方法中输出传递的整型值加10后的结果。

  2) 再创建一个类B,使其继承自类A,然后重写A中的MyMethod方法,将A中接

  收的整型值加50,并输出结果。

  3) 在Main方法中分别创建类A和类B的对象,并分别调用MyMethod方法。

  【解答】

  using System;

  public class A

  {

  public virtual void MyMethod(int num)

  {

  num += 10;

  Console.WriteLine(num);

  }

  }

  public class B : A

  {

  public override void MyMethod(int num)

  {

  num += 50;

  Console.WriteLine(num);

  }

  }

  class MainClass

  {

  public static void Main()

  {

  A newa = new A();

  newa.MyMethod(2);

  B newb = new B();

  newb.MyMethod(2);

  Console.ReadLine();

  }

  }

  输出结果:

  12

  52

  7. 假设Node类的每一个节点包括有两个字段:m_data(引用节点的数据)和m_next(引用链接列表中的下一项)。这两个字段都是由构造函数方法设置的。该类有两个功能,第一个功能是通过名为Data和Next的只读属性访问m_data和m_next字段。第二个功能是对System.Object的ToString虚拟方法进行重写。试分别用类和泛型两种方法编写程序实现上述功能。

  【解答】

  using System;

  class Node

  {

  Object m_data;

  Node m_next;

  public Node(Object data, Node next)

  {

  m_data = data;

  m_next = next;

  }

  // 访问结点数据

  public Object Data

  {

  get { return m_data; }

  }

  // 访问下一个结点

  public Node Next

  {

  get { return m_next; }

  }

  // 获取结点数据描述

  public override String ToString()

  {

  return m_data.ToString();

  }

  }

  // 链表结点类的泛型定义

  class Node

  {

  T m_data;

  Node m_next;

  public Node(T data, Node next)

  {

  m_data = data;

  m_next = next;

  }

  // 访问结点数据

  public T Data

  {

  get { return m_data; }

  set { m_data = value; }

  }

  // 访问下一个结点

  public Node Next

  {

  get { return m_next; }

  set { m_next = value; }

  }

  // 获取结点数据描述

  public override String ToString()

  {

  return m_data.ToString();

  }

  }

  // 使用结点类型或泛型结点类型

  class LinkedList

  {

  static void Main(string[] args)

  {

  //// 创建整数链表

  //Node head = new Node(5, null);

  //head = new Node(10, head);

  //head = new Node(15, head);

  ////遍历链表求整数和

  //Int32 sum = 0;

  //for (Node current = head; current != null;

  // current = current.Next)

  //{

  // sum += (Int32)current.Data;

  //}

  //// 输出结果

  //Console.WriteLine("Sum of nodes = {0}", sum);

  // 用泛型创建整数链表

  Node head = new Node(5, null);

  head = new Node(10, head);

  head = new Node(15, head);

  // 遍历求和

  Int32 sum = 0;

  for (Node current = head; current != null;

  current = current.Next)

  {

  sum += current.Data;

  }

  // 输出

  Console.WriteLine("Sum of nodes = {0}", sum.ToString());

  }

  }

#网络应用编程基础练习题与答案(5)

1. 填空题

  1) 使控件是否可以对用户交互作出响应的属性是 Enabled 。

  2) 控制控件是否显示的属性是 Visible 。

  3) 若要在文本框中输入密码,常指定 PasswordChar 属性。

  4) 若某复选框某时刻CheckState属性的值为Indeterminate,则其属性Checked的值为 Unchecked 。

  5) 使用 Panel 或 GroupBox 控件可以将多个RadioButton控件分为两个单选组。

  6) 若不希望用户在ComboBox控件中编辑文本,则应将属性 DropDownStyle 的属性值设置为DropDownList。

  7) 用于设置MenuStrip控件中某菜单项快捷键的属性是 ShortcutKeys 。

  8) 用于控制ListView控件中的各项显示方式的属性是 View 。

  2. 判断题

  1) 控件就是属性、方法和事件的集合封装体。 ( 对 )

  2) TextBox控件只能用于单行文本的输入。 ( 错 )

  3) 通过RichTextBox控件只能够与RTF文件进行交互操作。 ( 错 )

  4) CheckBox控件的Checked属性与CheckState属性的值始终是相同的。 ( 错 )

  5) ToolTip组件用于显示某指定控件的自定义提示信息的。 ( 对 )

  3. 区别TextBox控件、MaskedTextBox控件、RichTextBox控件的使用场合。

  【解答】

  TextBox控件一般用于单段文本的编辑,可以设置为单行或多行的输入模式,也可以用作密码的输入;MaskedTextBox控件主要用于特定格式的单段文本编辑,在输入文本不符合格式要求的将会触发其MaskInputRejected事件;RichTextBox控件除了具有TextBox的一般文本编辑功能外,还可以进行多段文本的高级编辑功能,如改变文本、段落的显示格式、在文本中查找特定字符和字符串以及与Rtf文件的交互等。

  4. 简要说明CheckBox控件和RadioButton控件的区别。

  【解答】

  CheckBox控件可为用户提供选择功能,常用的是二选一的选择,如“真/假”或“是/否”;但该控件也可以通过属性的设置作三选一的选择。每一个CheckBox所代表的选择都是独立的,若有多个CheckBox控件构成一组选项时,则可以多个同时被选中,相互之间不影响,即复选。RadioButton控件,它与CheckBox控件功能类似,也是用于接收用户的选择,但它是以单项选择的形式出现,即一组RadioButton按钮中只能有一个处于选中状态。一旦某一项被选中,则同组中其他RadioButton按钮的选中状态自动清除。

  5. 设计一个Windows应用程序,窗体上有一个TextBox控件、一个Button控件。要求,每当用户单击按钮时,文本框都会增加一行文字来反映单击的次数,例如“第3次单击按钮”。

  【解答】

  1) 窗体界面如图Ex5-5-1所示;

  2) 窗体中主要控件属性设置如表Ex5-5-1;

表Ex5-5-1 窗体中的主要控件属性

控件

Name属性

功能

其它属性

TextBox控件

textBox1

显示信息

ScrollBars=Vertical; Multiline=True

Button控件

Button1

触发添加信息事件

Button2

触发结束添加事件

  3) 主要事件代码。

  ……

  int i = 1;

  bool Add = true;

  ……private void button1_Click(object sender, EventArgs e)

  {

  if(Add) textBox1.Text += "第" + i + "次单击按钮\r\n";

  i++;

  }

  private void button2_Click(object sender, EventArgs e)

  {

  Add = false;

  }

  6. 编写一段程序,向ListBox控件listBox1中,自动添加10个数,每个数占一项。

  【解答】

  主要代码如下:

  public partial class Form1 : Form

  {

  int m = 1;

  ……

  private void button1_Click(object sender, EventArgs e)

  {

  for (int i = m ; i < m+10; i++)

  {

  listBox1.Items.Add(i);

  }

  m = m + 10;

  }

  }

  7. 参照Windows系统“附件”中的“计算器”,自行编写一个简易的计算器。要求:可以实现由0~4构成的整数的加减运算。

  【解答】

  1) 窗体界面如图Ex5-5-2所示;

  2) 将InputNumber事件作为button0、button1、button2、button3、button4的Click事件。

  完整代码如下:

  using System;

  using System.Collections.Generic;

  using System.ComponentModel;

  using System.Data;

  using System.Drawing;

  using System.Text;

  using System.Windows.Forms;

  namespace Exer2

  {

  public partial class FormCalculator : Form

  {

  enum calculateType { none, add, sub };

  calculateType myCal = calculateType.none;

  int x, y;

  bool isY = false;

  public FormCalculator()

  {

  InitializeComponent();

  textBox.TextAlign = HorizontalAlignment.Right;

  }

  private void InputNumber(object sender, EventArgs e)

  {

  Button num = (Button)sender;

  if (isY)

  {

  textBox.Clear();

  isY = false;

  }

  textBox.Text += num.Text;

  }

  private void buttonEqual_Click(object sender, EventArgs e)

  {

  y = Convert.ToInt32(textBox.Text);

  if (myCal == calculateType.add)

  {

  textBox.Text = Convert.ToString(x + y);

  myCal = calculateType.none;

  }

  if (myCal == calculateType.sub)

  {

  textBox.Text = Convert.ToString(x - y);

  myCal = calculateType.none;

  }

  isY = true;

  }

  private void addButton_Click(object sender, EventArgs e)

  {

  myCal = calculateType.add;

  x = Convert.ToInt32(textBox.Text);

  isY = true;

  }

  private void buttonSub_Click(object sender, EventArgs e)

  {

  myCal = calculateType.sub;

  x = Convert.ToInt32(textBox.Text);

  isY = true;

  }

  private void buttonClear_Click(object sender, EventArgs e)

  {

  textBox.Text = "";

  myCal = calculateType.none;

  isY = false;

  }

  }

  }

  8. 试利用TreeView、ListView等控件实现一个类似“资源管理器”的文档管理程序,用于查看C:\Documents and Settings目录下的文件。

  【解答】

  1) 新建一个名为WindowsControlsExercise的项目,在【解决方案资源管理器】中重命名文件Form1.cs为Explorer.cs,并设置Form1窗体的Text属性为“资源管理器”。

  2) 向窗体中添加一个SplitContainer控件、一个ImageList控件、一个TreeView控件、一个ListView控件,页面布局及各控件属性如图Ex5-5-3所示。

  3) 在【解决方案资源管理器】中,将imageList1控件中的两个图标文件添加到应用程序目录中,分别命名为folder.ico和doc.ico。

  4) 在Explorer.cs代码文件中添加命名空间:using System.IO,并添加构造函数代码如下:

  public Explorer()

  {

  InitializeComponent();

  PopulateTreeView();

  }

  private void PopulateTreeView()

  {

  TreeNode rootNode;

  DirectoryInfo info = new DirectoryInfo(@"C:\Documents and Settings");

  if (info.Exists)

  {

  rootNode = new TreeNode(info.Name);

  rootNode.Tag = info;

  GetDirectories(info.GetDirectories(), rootNode);

  treeView1.Nodes.Add(rootNode);

  }

  }

  private void GetDirectories(DirectoryInfo[] subDirs, TreeNode nodeToAddTo)

  {

  TreeNode aNode;

  DirectoryInfo[] subSubDirs;

  foreach (DirectoryInfo subDir in subDirs)

  {

  aNode = new TreeNode(subDir.Name, 0, 0);

  aNode.Tag = subDir;

  aNode.ImageKey = "folder";

  subSubDirs = subDir.GetDirectories();

  if (subSubDirs.Length != 0)

  {

  GetDirectories(subSubDirs, aNode);

  }

  nodeToAddTo.Nodes.Add(aNode);

  }

  }

  5) 添加treeView1的NodeMouseClick事件,使单击treeView1中某个节点时,用该节点的内容来填充listView1。

  private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)

  {

  TreeNode newSelected = e.Node;

  listView1.Items.Clear();

  DirectoryInfo nodeDirInfo = (DirectoryInfo)newSelected.Tag;

  ListViewItem.ListViewSubItem[] subItems;

  ListViewItem item = null;

  foreach (DirectoryInfo dir in nodeDirInfo.GetDirectories())

  {

  item = new ListViewItem(dir.Name, 0);

  subItems = new ListViewItem.ListViewSubItem[]

  {new ListViewItem.ListViewSubItem(item, "Directory"),

  new ListViewItem.ListViewSubItem(item,

  dir.LastAccessTime.ToShortDateString())};

  item.SubItems.AddRange(subItems);

  listView1.Items.Add(item);

  }

  foreach (FileInfo file in nodeDirInfo.GetFiles())

  {

  item = new ListViewItem(file.Name, 1);

  subItems = new ListViewItem.ListViewSubItem[]

  { new ListViewItem.ListViewSubItem(item, "File"),

  new ListViewItem.ListViewSubItem(item,

  file.LastAccessTime.ToShortDateString())};

  item.SubItems.AddRange(subItems);

  listView1.Items.Add(item);

  }

  listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

  }

  6) 按键编译并执行。

1. 简要回答文件和流之间的区别和联系。

  【解答】

  文件(file)和流(stream)即有区别又有联系。文件是在各种媒质上(可移动磁盘、硬盘、CD 等)永久存储的数据的有序集合。它是一种进行数据读写操作的基本对象。通常情况下,文件按照树状目录进行组织,每个文件都有文件名、文件所在路径、创建时间、访问权限等属性。

  流是字节序列的抽象概念,例如文件、输入输出设备、内部进程通信管道或者TCP/IP套接字等均可以看成流。流提供一种向后备存储器写入字节和从后备存储器读取字节的方式。

  2. Directory类为我们提供了哪些目录管理的功能,它们是通过哪些方法来实现的?

  【解答】

  Directory类为我们提供了对磁盘和目录进行管理的功能,如复制、移动、重命名、创建和删除目录,获取和设置与目录的创建、访问及写入操作相关的时间信息。

  如:CreateDirectory方法用于创建指定路径中的所有目录;Delete方法用于删除指定的目录;Move方法能够重命名或移动目录;Exists方法用于确定给定路径是否引用磁盘上的现有目录;GetCurrentDirectory方法用于获取应用程序的当前工作目录;GetFiles方法用于返回指定目录中的文件的名称等。

  3. 编写程序综合应用Directory类的主要方法。首先确定指定的目录是否存在,如果存在,则删除该目录;如果不存在,则创建该目录。然后,移动此目录,在其中创建一个文件,并对文件进行计数。

  【解答】

  程序清单如下:

  using System;

  using System.IO;

  class Test

  {

  public static void Main()

  {

  string path = @"c:\MyDir";

  string target = @"c:\TestDir";

  try

  {

  if (!Directory.Exists(path))

  {

  Directory.CreateDirectory(path);

  }

  if (Directory.Exists(target))

  {

  Directory.Delete(target, true);

  }

  Directory.Move(path, target);

  File.CreateText(target + @"\myfile.txt");

  Console.WriteLine("在{0}中的文件数目是{1}",

  target, Directory.GetFiles(target).Length);

  }

  catch (Exception e)

  {

  Console.WriteLine("操作失败: {0}", e.ToString());

  }

  finally {}

  }

  }

  4. 编写程序,将文件复制到指定路径,允许改写同名的目标文件。

  【解答】

  程序清单如下:

  using System;

  using System.IO;

  class Test

  {

  public static void Main()

  {

  string path = @"c:\temp\MyTest.txt";

  string path2 = path + "temp";

  try

  {

  using (FileStream fs = File.Create(path)) {}

  File.Delete(path2);

  File.Copy(path, path2);

  Console.WriteLine("{0}拷贝到:{1}", path, path2);

  File.Copy(path, path2, true);

  Console.WriteLine("第二次拷贝成功");

  }

  catch

  {

  Console.WriteLine("重复拷贝不允许");

  }

  }

  }

  5. 编写程序,使用File类实现删除当前目录下的所有文件。

  【解答】

  程序清单如下:

  using System;

  using System.IO;

  class FileTest

  {

  public static void Main()

  {

  Console.WriteLine("确认删除当前目录下的所有文件?");

  Console.WriteLine("点击'Y'键继续,其它键取消操作");

  int a = Console.Read();

  if(a == 'Y' || a == 'y'){

  Console.WriteLine("正在删除文件...");

  }

  else

  {

  Console.WriteLine("用户取消操作");

  return;

  }

  DirectoryInfo dir = new DirectoryInfo (".");

  foreach (FileInfo f in dir.GetFiles())

  {

  f.Delete();

  }

  }

  }

1. 解释正则表达式 <a\s+href\s*=\s*""?([^"" >]+)""?>(.+)</a>各部分代表的含义。

  【解答】 此正则表达式用于匹配源文件中类似于搜狐新闻的字符串,各部分表示的含义为:

  \s+ 一个或多个空白字符

  href 后接 HTML 定位点中的确切文本

  \s* 零个或多个空白字符

  = 后接 HTML 定位点中的确切文本

  \s* 零个或多个空白字符

  ""? 零或无引号(转义的)

  ( 定义子字符串(定位点 URL)的组的起始点。

  [^"" >]+ 任意字符的一个或多个匹配项,括号中的字符除外。

  ) 定义子字符串的第一组的结束

  ""? 零或无引号(转义的)

  > 后接 HTML 定位点中的确切文本

  (.+) 与任意字符(定位点文本)匹配的组。

  结束 HTML 定位点的确切文本

  2. 下面是检查输入字符串是否为有效的电子邮件的正则表达式:

  ^([\w-]+\.)*?[\w-]+@[\w-]+\.([\w-]+\.)*?[\w]+$

  试解释各部分的含义。

  【解答】

  [\w-]+

  一个或多个任意字符(a-z、A-Z、0-9 以及下划线)或短划线。在@字符两边,确保地址形式为name@domainname。

  \.

  一个转义点号。(不带反斜杠,一个点号与除换行符外的任意单个字符匹配。)以此确保域名中至少有一个点号。

  *?

  对前面的表达式,非贪婪(non-greedy,即最小)地查找零次或多次匹配。

  ([\w-]+\.)*?

  以上三个表达式的组合:

  对于包含一个或多个任意字符(a-z、A-Z、0-9 以及下划线)或短划线并且后面只跟一个点号的表达式,非贪婪地查找零次或多次匹配。

  3. 写出符合下列要求的正则表达式:

  1) 要求4-8个英文字母。

  2) 不能包含字母,至少1个字符。

  3) 至少3个数字。

  4) 至少3个字符。

  5) 至少3个英文字母。

  6) 任意字符。

  7) 3个字母或数字,如123,r3a等。

  8) 3个点。

  9) @前至少有1个字符,@后至少有3个字符。

  10) 必须输入左括号。

  【解答】

  1) [a-zA-Z]{4,8}

  2) [^a-zA-Z]{1,}

  3) [0-9]{3,}

  4) {3,}

  5) [a-zA-Z]{3,}

  6) .{0,}

  7) [A-Za-z0-9]{3}

  8) \.{3}

  9) .{1,}@ .{3,}

  10) \(

C#网络应用编程基础练习题与答案(8)

1. 使用保持连接的方式编写程序,计算各年级平均成绩,并显示结果。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.ComponentModel;

  using System.Data;

  using System.Drawing;

  using System.Text;

  using System.Windows.Forms;

  using System.Data.SqlClient;

  namespace 习题8_6_1

  {

  public partial class Form1 : Form

  {

  public Form1()

  {

  InitializeComponent();

  }

  //添加Button按钮在ListBox中显示结果

  private void button1_Click(object sender, EventArgs e)

  {

  listBox1.Items.Add("年级 平均成绩");

  string connectionString = Properties.Settings.Default.MyDatabaseConnectionString;

  //根据连接字符串创建SqlConnection实例

  SqlConnection conn = new SqlConnection(connectionString);

  //创建SqlCommand实例,并设置SQL语句和使用的连接实例

  SqlCommand cmd = new SqlCommand();

  cmd.CommandText = "select substring(学号,1,2) as 年级,avg(成绩) as 平均成绩 from MyTable2 group by substring(学号,1,2)";

  cmd.Connection = conn;

  try

  {

  conn.Open();

  SqlDataReader r = cmd.ExecuteReader();

  while (r.Read() == true)

  {

  listBox1.Items.Add(string.Format("{0}级 {1}", r[0], r[1]));

  }

  r.Close();

  }

  catch (Exception err)

  {

  MessageBox.Show(err.Message, "计算成绩失败");

  }

  finally

  {

  conn.Close();

  }

  }

  }

  }

  2. 使用保持连接的方式编写程序,查询MyTable2中不及格学生的学号,姓名,性别,成绩。并将结果在ListBox中显示出来。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.ComponentModel;

  using System.Data;

  using System.Drawing;

  using System.Text;

  using System.Windows.Forms;

  using System.Data.SqlClient;

  namespace 习题8_6_2

  {

  public partial class Form1 : Form

  {

  public Form1()

  {

  InitializeComponent();

  }

  private void button1_Click(object sender, EventArgs e)

  {

  listBox1.Items.Add(" 学号 姓名 性别 成绩");

  string connectionString = Properties.Settings.Default.MyDatabaseConnectionString;

  //根据连接字符串创建SqlConnection实例

  SqlConnection conn = new SqlConnection(connectionString);

  //创建SqlCommand实例,并设置SQL语句和使用的连接实例

  SqlCommand cmd = new SqlCommand();

  cmd.CommandText =

  "Select 学号,姓名,性别, 成绩 From MyTable2 Where (成绩<60)";

  cmd.Connection = conn;

  try

  {

  conn.Open();

  SqlDataReader r = cmd.ExecuteReader();

  while (r.Read() == true)

  {

  listBox1.Items.Add( string.Format("{0} {1} {2} {3}", r[0], r[1], r[2], r[3]));

  }

  r.Close();

  }

  catch (Exception err)

  {

  MessageBox.Show(err.Message, "查询成绩失败");

  }

  finally

  {

  conn.Close();

  }

  }

  }

  }

  3. 编写程序,以“[编码]名称”的样式在comboBox1中显示MyTable1的内容。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.ComponentModel;

  using System.Data;

  using System.Drawing;

  using System.Text;

  using System.Windows.Forms;

  using System.Data.SqlClient;

  namespace 习题8_6_3

  {

  public partial class Form1 : Form

  {

  public Form1()

  {

  InitializeComponent();

  }

  private void Form1_Load(object sender, EventArgs e)

  {

  string connectionString = Properties.Settings.Default.MyDatabaseConnectionString;

  //根据连接字符串创建SqlConnection实例

  SqlConnection conn = new SqlConnection(connectionString);

  //创建SqlCommand实例,并设置SQL语句和使用的连接实例

  SqlCommand cmd = new SqlCommand();

  cmd.CommandText = "Select * From MyTable1";

  cmd.Connection = conn;

  try

  {

  conn.Open();

  SqlDataReader r = cmd.ExecuteReader();

  while (r.Read() == true)

  {

  comboBox1.Items.Add(string.Format("[{0}] {1}", r[0], r[1]));

  }

  comboBox1.SelectedIndex = 0;

  r.Close();

  }

  catch (Exception err)

  {

  MessageBox.Show(err.Message, "显示数据失败");

  }

  finally

  {

  conn.Close();

  }

  }

  }

  }

  4. 在画线处填上合适的内容,使程序变得正确完整。

  string connString="server=localhost;Integrated Security=SSPI;database=pubs";

  SqlConnection conn=____________________________

  string strsql="select * from MyTable2";

  SqlDataAdapter adapter=new SqlDataAdapter(_____________);

  dataset=new DataSet();

  adapter.Fill(________________,"MyTable2");

  this.dataGridView1.DataSource=dataset.Tables["MyTable2"];

  【解答】

  string connString="server=localhost;Integrated Security=SSPI;database=pubs";

  SqlConnection conn= new SqlConnection(Properties.Settings.Default.MyDatabaseConnectionString);

  string strsql="select * from MyTable2";

  SqlDataAdapter adapter=new SqlDataAdapter(conn);

  dataset=new DataSet();

  adapter.Fill(dataset,"MyTable2");

  this.dataGridView1.DataSource=dataset.Tables["MyTable2"];

  5. 已知数据库中定义了一张person表,表的数据结构如下:

  字段名称字段类型字段含义

  id数字编号

  xm文本姓名

  xb文本性别

  nl数字年龄

  zip文本邮政编码

  用编写代码的方法在DataGridView中显示该数据表中年龄大于18的所有纪录,显示时以编号的升序排序,要求禁止用户编辑数据。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.ComponentModel;

  using System.Data;

  using System.Drawing;

  using System.Text;

  using System.Windows.Forms;

  using System.Data.SqlClient;

  namespace 习题8_6_5

  {

  public partial class Form1 : Form

  {

  public Form1()

  {

  InitializeComponent();

  }

  private void button1_Click(object sender, EventArgs e)

  {

  string connectionstring = Properties.Settings.Default.MyDatabaseConnectionString ;

  SqlConnection conn = new SqlConnection(connectionstring);

  try

  {

  conn.Open();

  SqlDataAdapter adapter = new SqlDataAdapter(

  "select id,xm,xb,nl from person where nl > 18 order by id", conn);

  DataSet dataset = new DataSet();

  //如果不指定表名,则系统自动生成一个默认的表名

  adapter.Fill(dataset, "person");

  //可以使用索引引用生成的表

  dataGridView1.DataSource = dataset.Tables["person"];

  adapter.Dispose();

  }

  catch (Exception err)

  {

  MessageBox.Show(err.Message);

  }

  finally

  {

  conn.Close();

  }

  }

  private void Form1_Load(object sender, EventArgs e)

  {

  //不允许用户直接在最下面的行添加新行

  dataGridView1.AllowUserToAddRows = false;

  //不允许用户直接按Delete键删除行

  dataGridView1.AllowUserToDeleteRows = false;

  }

  }

  }

  6.例8-18的存储过程定义中,将“@surname nvarchar(2),”改为“@surname nchar(2),”,是否仍然能够得到正确结果,为什么?

  【解答】

  不一定。因为如果传递的参数值为“王”,在存储过程中会自动变为“王 ”。

  7. 调用存储过程,设计程序完成下列功能:任意给出一个汉字,统计MyTable2中所有包含该汉字的人数,并显示统计结果。

  【解答】

  using System;

  using System.Collections.Generic;

  using System.ComponentModel;

  using System.Data;

  using System.Drawing;

  using System.Text;

  using System.Windows.Forms;

  using System.Data.SqlClient;

  namespace 习题8_6_7

  {

  public partial class Form1 : Form

  {

  public Form1()

  {

  InitializeComponent();

  }

  private void button1_Click(object sender, EventArgs e)

  {

  SqlConnection conn =

  new SqlConnection(Properties.Settings.Default.MyDatabaseConnectionString);

  SqlCommand cmd = new SqlCommand();

  cmd.Connection = conn;

  //设置SQL语句为存储过程名,命令类型为存储过程

  cmd.CommandText = "SelectFilterStudentsNum";

  cmd.CommandType = CommandType.StoredProcedure;

  //添加存储过程中参数需要的初始值,注意参数名要和存储过程定义的参数名相同

  if( textBox1.Text=="")

  {

  MessageBox.Show("请输入有效信息","错误");

  textBox1.Focus();

  return ;

  }

  cmd.Parameters.AddWithValue("@surname", textBox1.Text);

  cmd.Parameters.AddWithValue("@record", 0);

  //指定哪些参数需要返回结果

  cmd.Parameters["@record"].Direction = ParameterDirection.Output;

  try

  {

  conn.Open();

  //执行存储过程

  cmd.ExecuteNonQuery();

  //显示返回的结果

  MessageBox.Show(string.Format("有{0}条含 {1} 的记录",

  cmd.Parameters["@record"].Value,textBox1.Text));

  }

  catch (Exception err)

  {

  MessageBox.Show(err.Message);

  }

  finally

  {

  conn.Close();

  }

  }

  }

  }

1. 简述三类二维坐标系统之间的相同点和区别。

  【解答】

  GDI+中的二维笛卡儿坐标系统分为三类:全局坐标系统、页面坐标系统和设备坐标系统。

  三类坐标系统的相同点:它们都有坐标原点以及向右和向下的x轴和y轴。

  三类坐标系统的区别:全局坐标系统可以进行旋转、平移等操作。页面坐标系统与设备坐标系统都是以设备的左上角为坐标原点,X水平向右为正,Y垂直向下为正。页面坐标系统与设备坐标系统的差异在于X,Y的单位不同:页面坐标系中的X,Y单位可以任意设定,如英寸、毫米等;而设备坐标系中,只有一种单位,那就是点(point)或者像素(pixel)。页面坐标系是不能更改的,它是一个参照标准,将全局坐标最终转换为设备坐标。

  2. 简述创建Graphics类对象的三种方法。

  【解答】

  (1) 在窗体或控件的Paint事件中直接引用Graphics对象。在为窗体创建绘制代码时,一般使用此方法获取对图像的引用。

  (2) 从当前窗体获取对Graphics对象的引用。注意这种对象只有在处理当前Windows窗体消息的过程中有效。如果想在已经存在的窗体或控件中绘图,可以使用此种方法。

  (3) 从继承自图像的任何对象创建Graphics对象。这个方法适用于需要更改已经存在的

  图像。

  3. 同时创建多个矩形并用红黑相间的颜色进行填充。

  【解答】

  (1) 新建一个Windows应用程序,命名为“FillMultiRectangle”,调整窗体到适当大小。更改“Form1.cs”为“FormFillMultiRectangle.cs”。

  (2) 切换到代码方式,添加名称空间引用:

  using System.Drawing.Drawing2D;

  (3) 双击窗体的属性面板里事件页中的Paint事件,添加FormFillMultiRectangle_Paint事件代码。

  private void FormFillMultiRetangle_Paint(object sender, PaintEventArgs e)

  {

   Graphics g = e.Graphics;

  HatchBrush mybrush=new HatchBrush (HatchStyle.Cross,Color .Red,Color .Black);

  Rectangle[] rect=

  {

  new Rectangle( 0, 0, 50, 100),

  new Rectangle(50,100, 100, 50),

  new Rectangle(150, 150, 50, 100),

  };

  g.FillRectangles(mybrush, rect);

  g.Dispose();

  }

  (4) 结果如图所示。

  4. 使用Label控件分别以矩形、椭圆和圆形的方式显示图片,并保证图片完全由绘制对象的边框决定。

  【解答】

  (1)新建一个Windows应用程序,命名为“ShowImageExe”,调整窗体到适当大小。更改“Form1.cs”为“FromShowImageExe.cs”。

  (2)切换到代码方式,添加名称空间引用:

  using System.Drawing.Drawing2D;

  (3) 添加四个Button控件分别命名为“buttonOpenFile”、“buttonRectangle”、“buttonEllipse”、“buttonRound”,以及一个openFileDiolog和label控件。

  (4)在Form类下声明两个私有变量filename和flag,分别用来记录打开的文件名和判断哪个按钮的click时间被触发。

  private string filename = "";

  private int flag = 0;

  (5) 添加【打开文件】按钮的click事件

  private void buttonOpenFile_Click(object sender, EventArgs e)

  {

  openFileDialog1.ShowDialog();

  filename = openFileDialog1.FileName;

  label1.Refresh();

  }

  (6) 在label1控件的paint事件下添加如下代码:

  private void label1_Paint(object sender, PaintEventArgs e)

  {

  if (filename.Trim() == "")

  return;

  Bitmap mybitmap = new Bitmap(filename);

  Graphics g = e.Graphics;

  TextureBrush mybrush = new TextureBrush(mybitmap,WrapMode.Clamp);

  //保证图片完全由绘制对象的边框决定

  switch (flag)

  {

  case 1:

  g.FillRectangle(mybrush, label1.ClientRectangle);

  break;

  case 2:

  g.FillEllipse(mybrush, label1.ClientRectangle);

  break;

  case 3:

  g.FillEllipse(mybrush, (label1.Width- label1.Height)/2,0, label1.Height, label1.Height);

  break;

  }

  }

  (7) 在其他几个按钮的click事件中分别添加如下代码:

  private void buttonRectangle_Click(object sender, EventArgs e)

  {

  flag = 1;

  label1.Refresh();

  }

  private void buttonEllipse_Click(object sender, EventArgs e)

  {

  flag = 2;

  label1.Refresh();

  }

  private void buttonRound_Click(object sender, EventArgs e)

  {

  flag = 3;

  label1.Refresh();

  }

  

  (8) 结果如图所示。

  5. 利用PictureBox控件和Panel控件实现使用滚动条浏览大图片。

  【解答】

  由于Picturebox控件在显示图片时不能直接使用滚动条,所以必须借助Panel控件实现以滚动条的方式浏览大图片。具体操作步骤如下:

  (1)新建一个Windows应用程序,命名为“scrollBar”,调整窗体到适当大小。更改“Form1.cs”为“FormScrollBar.cs”。

  (2)切换到代码方式,添加名称空间引用:

  using System.Drawing.Drawing2D;

  (3) 在窗体上分别添加一个button控件命名为“buttonOpenFile”,一个openFileDiolog控件,Picturebox和Panel控件各一个,将Panel控件的AutoScroll属性设为true。

  (4) 在“buttonOpenFile”控件的click事件中添加如下代码:

  private void buttonOpenFile_Click(object sender, EventArgs e)

  {

  openFileDialog1.ShowDialog();

  if (openFileDialog1.FileName.Trim() == "")

  return;

  try

  {

  Bitmap mybitmap = new Bitmap(openFileDialog1.FileName);

  pictureBox1.Image = mybitmap;

  }

  catch (Exception Err)

  {

  MessageBox.Show("打开文件错误!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

  }

  }

  (5) 结果如图所示。

  

  6. 实现对图片按任意角度进行旋转、按任意比例进行缩放、按任意位移进行平移。

  【解答】

  (1) 在窗体上添加六个label控件(其中label1用来显示图片)、一个button控件(用于打开图片文件)和五个numericUpDown控件(分别用来选择图片缩放的比例、图片旋转的角度、图片位移的大小)。

  (2) 在构造函数上方添加代码:

  private string strfilename="";

  (3) 在button控件的click事件里添加如下代码:

  private void button1_Click(object sender, EventArgs e)

  {

  openFileDialog1.ShowDialog();

  strfilename=openFileDialog1.FileName;

  label1.Refresh();

  }

  (4) 在每一个numericUpDown控件的ValueChanged事件中添加如下代码:

  label1.Refresh();

  (5) 在label1控件的paint事件中添加如下代码:

  private void label1_Paint(object sender, PaintEventArgs e)

  {

  if (this.strfilename.Trim()=="")

  return ;

  try

  {

  Bitmap mybitmap = new Bitmap(strfilename);

  Graphics g = e.Graphics;

  TextureBrush mybrush = new TextureBrush(mybitmap);

  float x = (float)(numericUpDownS1.Value / 100);

  float y = (float)(numericUpDownS2.Value / 100);

  mybrush.ScaleTransform(x, y);

  g.FillRectangle(mybrush, 0, 0, ClientRectangle.Width, ClientRectangle.Height);

  float r = (float)(numericUpDownR1.Value);

  mybrush.RotateTransform(r);

  g.FillRectangle(mybrush, 0, 0, ClientRectangle.Width, ClientRectangle.Height);

  float tx = (float)(numericUpDownT1.Value);

  float ty = (float)(numericUpDownT2.Value);

  mybrush.TranslateTransform(tx, ty);

  g.FillRectangle(mybrush, 0, 0, ClientRectangle.Width, ClientRectangle.Height);

  }

  catch (Exception Err)

  {

  MessageBox.Show("打开文件错误!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

  }

  }

  8-8-6

C#网络应用编程基础练习题与答案

1. 组件与控件的主要区别是什么?

  【解答】

  组件是指可重复使用并且可以和其他对象进行交互的对象。组件(component)是靠类实现的。控件是能够提供用户界面接口(UI)功能的组件。换句话说就是,控件是具有用户界面功能的组件。

  所有控件肯定都是组件,但并不是每个组件都一定是控件。

  2. 控件有几种类型?各有什么特点?

  【解答】

  控件分为:复合、扩展和自定义三类。

  复合控件是封装在公共容器内的Windows窗体控件的集合。这种控件有时称为“用户控件”,包含的控件称为“构成控件”。复合控件包含与每个包含的Windows窗体控件相关联的所有固有功能,允许有选择地公开和绑定它们的属性。复合控件还提供了大量的默认键盘处理功能,不需要任何额外的开发。复合控件从UserControl类派生而来。

  扩展控件是从任何现有的Windows窗体控件或者自定义控件导出的继承控件。它保留Windows窗体控件的所有固有功能,然后通过添加自定义属性、方法或其他功能扩展此固有功能。可以使用此选项重写基控件的绘制逻辑,然后更改该控件的外观以扩展其用户界面。

  创建控件的另一种方法是通过从Control继承从头开始创建一个控件。Control类提供控件所需的所有基本功能(包括鼠标和键盘处理事件),但不提供控件特定的功能或图形界面。若要实现自定义控件,必须编写该控件的OnPaint事件的代码,以及所需的任何功能特定的代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: