Neil Cowburn
Content Master Ltd
2003年3月
适用于:
Microsoft® .NET Framework 精简版 1.0
Microsoft Visual Studio® .NET 2003
摘要:学习如何通过一些简单的优化技术来减少 .NET Framework 精简版 Windows 窗体应用程序加载所需的时间。
目录
简介
默认的 Forms Designer(窗体设计器)生成的代码不能始终创建适用于创建 Microsoft® Windows® 窗体的最优代码。但是,执行一些操作可以帮助优化生成的代码。通过编写自己的窗体初始化代码,可以改进窗体的加载性能。
此外,通过重新排列和/或覆盖由 Microsoft Visual Studio® .NET 中的 Forms Designer(窗体设计器)生成的代码,可以显著提高应用程序整个窗体的加载性能。
警告:请勿在修改 InitializeComponent 后使用设计器。
InitializeComponent 方法前有一个注释,警告您不要修改代码。如果修改 InitializeComponent 方法中的代码,将无法再使用 Forms Designer(窗体设计器)。如果使用 Forms Designer(窗体设计器),所做的修改将丢失。只应在开发的最后阶段,完成所有设计工作后,再执行这些优化。
本文假定您在 Microsoft .NET Framework 精简版和 Microsoft Visual C#® .NET 方面有一定的使用经验,并且已安装了 Visual Studio .NET 2003。
测量性能
要测量窗体初始化代码的性能,可以使用一个简单的测试来测量初始化窗体控件所需的时间。通过记录调用 InitializeComponent 方法前后系统计时器的刻度计数,可以记录初始化窗体控件所需的时间。为此,您可以通过 Platform Invoke (P/Invoke) 使用 coredll.dll 中的 GetTickCount() API 调用。
// GetTickCount() 的 API 原型
[DllImport("coredll.dll", EntryPoint="GetTickCount")]
public static extern uint GetTickCount();
// 窗体构造函数
public Form1()
{
uint startTickCount, endTickCount, timeTaken;
// 调用 GetTickCount 获取起始刻度计数
startTickCount = GetTickCount();
// 初始化窗体中的控件
InitializeComponent();
// 再次调用 GetTickCount 获取最终的刻度计数
endTickCount = GetTickCount();
// 计算初始化控件所用的时间(以毫秒为单位)
timeTaken = startTickCount - endTickCount;
// 在消息框中显示所用的时间
MessageBox.Show("加载时间:" + timeTaken.ToString() + "毫秒");
}
减少方法调用的数目
提高窗体加载性能的方法之一是减少窗体初始化期间生成的方法调用的数目。例如,Forms Designer(窗体设计器)生成的用于设置控件的位置和大小的代码使用两个方法调用来设置这些属性,如下所示:
this.textBox1.Location = new Point(10,20);
this.textBox1.Size = new Size(72,23);
使用 Bounds 属性可以将这两个方法调用统一成一个方法调用:
this.textBox1.Bounds = new Rectangle(10,20,72,23);
要显示可实现的性能增益,请考虑创建一个窗体,其中包含 1 个 MenuBar、1 个 TabControl 控件、5 个 TabPage(各包含 7 个 Label、7 个 Button 和 7 个 TextBox)。总共是 112 个控件。此应用程序是使用 Release(发行)配置文件生成的,并部署到 Pocket PC 2002 仿真器,此应用程序在仿真器中运行 5 次,下面是整理的各次运行时间的比较。
表 1:Forms Designer(窗体设计器)生成的代码计时
| 第次 |
初始化控件的时间(毫秒) |
| 1 |
14275 |
| 2 |
13950 |
| 3 |
15475 |
| 4 |
15175 |
| 5 |
14325 |
| 平均时间(毫秒): |
14630 |
注意:在实际设备上获得的性能要远高于此。
应用上述的方法调用优化时,将记录以下计时:
表 2:方法调用优化的代码计时
| 第次 |
初始化控件的时间(毫秒) |
| 1 |
13225 |
| 2 |
13850 |
| 3 |
13000 |
| 4 |
13625 |
| 5 |
13100 |
| 平均时间(毫秒): |
13360 |
与 Forms Designer(窗体设计器)生成的代码相比,性能提高了将近 9%。
自上而下地创建控件
提高性能的另一种方法是在控件树中自上而下地初始化控件。例如,如果有一个包含许多控件的面板控件,请先创建面板,然后在面板上添加控件。同样,设置控件的父属性而不是添加至控件集合,也可以提高性能。例如,请考虑在面板的控件集合中添加一个文本框:
// 优化前
// 创建一个新面板和文本框控件
Panel panel1 = new Panel();
TextBox textBox1 = new TextBox();
// 设置 TextBox 控件的 Text 属性
textBox1.Text = "我的文本";
// 将 TextBox 添加至面板的控件集合中
panel1.Controls.Add(this.textBox1);
// 将面板添加至窗体的控件集合中
this.Controls.Add(panel1);
... // 在此处添加后续控件
使用自上而下和父级处理技术优化此代码片断将生成以下代码片断:
// 优化后
// 创建一个新面板和文本框控件
Panel panel1 = new Panel();
TextBox textBox1 = new TextBox();
// 使当前窗体成为面板的父级
this.panel1.Parent = this;
// 使面板成为 TextBox 的父级
this.textBox1.Parent(this.panel1);
// 设置 TextBox 控件的 Text 属性
textBox1.Text = "我的文本";
... // 在此处添加后续控件
综合使用以上技术对深层嵌套的控件层次结构具有重要影响。
通过自上而下创建控件并重新分配父关系来优化 InitializeComponent 方法中的代码,将生成以下数据:
表 3:自上而下优化的代码计时
| 第次 |
初始化控件的时间(毫秒) |
| 1 |
7425 |
| 2 |
7450 |
| 3 |
7225 |
| 4 |
7375 |
| 5 |
7500 |
| 平均时间(毫秒): |
7395 |
与默认的 Forms Designer(窗体设计器)生成的代码相比,性能提高了将近 49%。
如果将两种优化技术组合使用,将获得以下计时结果:
表 4:组合后的优化代码计时
| 第次 |
初始化控件的时间(毫秒) |
| 1 |
6625 |
| 2 |
6600 |
| 3 |
6575 |
| 4 |
6475 |
| 5 |
6750 |
| 平均时间(毫秒): |
6605 |
与 Forms Designer(窗体设计器)生成的代码相比,将方法调用优化与自上而下的控件初始化技术组合使用可以使整体性能提高将近 55%。如果应用程序包含复杂的窗体,并且您希望提高窗体的加载性能,则在代码中应用这些优化将很有帮助。
更多信息
有关其他信息,请参阅以下资源: