** 创建应用自定义控件的 ** ** WinForm ** ** 工程 ** ** **
1. 在 File 菜单中点击 New ,然后点击 Project 。
2. 在左边的窗口中选择 Visual C# Projects 。
3. 在右边的窗口中选择 Window Application (这个 Application 里将应用我们的例子)。
4. 将工程命名为 DesignTimeDebugging 。
5. 确定 radio button 选择的是 Add to solution 。
** 为工程添加我们的控件库的引用 ** ** **
1. 在我们的 Host App Project 中,右击 References ,点击 Add Reference 。
2. 在 Projects 属性页上,选择 Immedient.Windows.Forms 工程。
** 使用我们的自定义 ** ** Form **
1. 为了能够使用 Microsoft IntelliSense ,我们重新编译我们的工程。
2. 使用下面的代码改变 Form1 的继承关系,改由我们自定义的 Form 派生。
C#
namespace Immedient.Samples.HostApp.Windows
{
public class Form1 : Immedient.Windows.Forms.Form
{
3. 打开 Form1 ,会发现我们自定义的属性出现在了属性页上。如果有错误发生,关闭所有代开的文件,然后 Rebuild Solution ,再重新打开 Form1 。
** 设置控件库工程的属性 ** ** **
通常我们希望能够确定我们是否产生了 VS.NET 调试我们的代码所需的信息。当开始调试时,如果在断点上开到“ ? ”符号,说明我们没有产生合适的符号文件。这可能是由于当前正处于 Release 模式下,或者工程设置被偶然改变了。应当确定 Generate Debugging Information 属性被设为 true 。
** Xml ** ** 文档( ** ** C# Only ** ** ) ** ** **
下面的设置只对 C# 有效,在 VS.NET2002 中, VB.NET 并不能产生 Xml 文档。
为了从我们在 C# 代码中创建的 Xml 注释中受益,我们应当告诉 VS.NET 生成一个 Xml 文档。将 XML Documentation File 属性设为与 Assembly 的名字加上 xml 后缀相同的值。
这里还用一个关于 Xml 文档的小窍门。你一旦设置了 XML Documentation File , VS.NET 会帮你为每个没有 Xml 注释的 public interface 产生警告。这些警告有时多的烦人。如果你还没有准备好处理所有 public interface 的文档的话,你可以将 Warning Level 设置为 2 ,这样,任务列表就不会收集警告信息,直到你将所有的事情都准备妥当之后,在将它设回来即可。
** 开始调试 ** ** **
现在我们有了一些可以调试的代码,让我们开始吧。为了调试我们的代码,我们需要步入( step into )容纳我们代码的应用程序中。在我们的示例中是 VS.NET 。
** 设置调试属性 ** ** **
在调试过程中,我们需要改变一些调试属性。它们在 VB.NET 和 C# 中有些许不同(译注:在此谨以 C# 为例)。
** C# ** ** 工程属性页 ** ** **
1. 右击 Control Library 工程,选择 Property 。
2. 点击 Configuration Properties 。
3. 将 Debug Mode 改为 Program 。
4. 将 Start Application 改为 Visual Studio .NET 。默认的位置是: C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe 。
** 设置断点 ** ** **
在自定义属性的 set 中的 if 表达式上设置断点
** 最后一件事 ** ** **
确保 Control Library 工程是启动工程。在 Control Library 工程上右击选择 Set as Startup Project 。
** 继续下去 ** ** **
1. 按 F5 开始调试过程。这时会有一个新的 VS.NET 实例被启动,我们的开发环境掌握此实例—— pretty cool 。
2. 分辨哪个 VS.NET 是我们的调试环境的一个简便方法是看调试按钮。调试环境中的 start button 是灰色无效的。
3. 当新的 VS.NET 启动之后,打开相同的 solution : C:\DesignTimeDebugging\DesignTimeDebugging.sln
4. 在 HostApp Windows Forms 工程中,双击 Form1 打开之。
5. 在属性页中,改变 MyText 属性的值为 Good bye 。
6. 此时应当步入断点所在处。
7. 我们已经调试了我们的第一个 .NET design-time control 。现在让我们看一看发生在后台的一系列事件。
** 事件链条 ** ** **
在使用设计时控件时,当你将一个控件拖到设计界面上时,明白在它背后发生了什么是很重要的。你肯定很想知道,当你创建一个从同样是你创建的另一个 Form 派生的 Form 是发生了什么。
当一个对象被在设计环境中打开时,这个对象所继承的那个类(不是新生成的类)被 VS.NET 构造。记住,这个被创建的控件激活( fire )它的构造函数,构造函数又激活了它的基类的构造函数中的 InitializeComponent() 方法。一旦派生类被构造,那个在新建类中具有神奇的名字的方法, InitializeComponent() ,将被 VS.NET 一行一行地解析。这个方法唯一神奇的是它的名字,因为 VS.NET 知道寻找这个方法。
在 VB.NET 中,如果 VS.NET 不能解析某行代码,那么这一行将被删除。这时由于 VB 开发小组觉得保持设计时环境更重要。而 C# 开发小组认为保持代码更重要,因此在 C# 中,如果 VS.NET 不能解析 InitializeComponent() ,你将会得到一个描述异常的文本。
当 InitializeComponent() 运行时,属性的值将被改成你在属性页上所设置的值。在 VS.NET 中,对象的属性页只是 InitializeComponent() 方法的图形化表示而已。如果你的基类的构造函数要完成一些特殊的功能,要小心了,这些功能也同样会被设计环境执行。
有一个方法可以使这些代码在设计时不被执行。任何派生自 Component 类的 class 都具有一个 DesignMode 属性。当对象在 VS.NET designer 中被构造时,这个属性被设为 true 。因此,你可以写一个 if 来包装你的代码,从而避免他们被执行。但是也没有更多的花招了, DesignMode 不会再构造函数中设为 true 。记住,这里根本没有魔法。 VS.NET 通过解析 InitializeComponent() 方法来构造对象,一旦对象被构造, VS.NET 将保持对对象的跟踪,并简单地设置:
newlyCreatedObject.DesignMode = true
为了增加一些乐趣,同时了事都有哪些事件会发生,以及 DesignMode 何时会被设置,在你的 Immedient.Windows.Forms.Form 中添加如下代码(译注:请用 VS.NET 来添加事件,这可以保证事件被正确添加到 InitializeComponent 方法中)。为了能够获得 VS.NET 发出的事件,请关闭所有的 Form ,重新编译 Solution 。
private void Form_Layout(object sender, System.Windows.Forms.LayoutEventArgs e)
{
MessageBox.Show("Layout: DesignMode = " + this.DesignMode.ToString());
}
private void Form_Load(object sender, System.EventArgs e)
{
if(this.DesignMode)
{
// Don't connected to database.
MessageBox.Show("Form load: DesignMode = " + this.DesignMode.ToString());
}
else
{
// Make a connection to database and do something.
MessageBox.Show("Form load: DesignMode = " + this.DesignMode.ToString());
}
}
private void Form_VisibleChanged(object sender, System.EventArgs e)
{
MessageBox.Show("VisibleChanged: DesignMode = " + this.DesignMode.ToString());
}
private void Form_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
MessageBox.Show("Paint: DesignMode = " + this.DesignMode.ToString());
}
** 总结 ** ** **
在这篇文章里,我们在 Windows Form 上使用了一个简单的属性。由此可以看出,在设计时环境中,任何东西的改变都是可以被调试的。我最初发现这个技巧,是在开发一个 ASP.NET Image HREF 设计时控件的时候。同样的技巧也适用于系统组件控件,比如 EventLog 控件和显示于系统托盘里的 Data 控件。 VS.NET 为开发控件提供了一个丰富、高效的开发环境,在这里,创建和调试控件就如同毁灭他们一样简单。
** 关于作者 ** ** **
Steve Lasker 是 Immedient 公司的 National Director of Research & Development 。 Steve 曾经为 Windows Forms , ASP.NET ,和 the .NET Compact Framework 开发过一些 .NET <SPAN style="FO