UML软件工程组织

如何在.NET中调试设计时(design-time)控件(下)  
sam1111(翻译)(选自微软中国)

创建应用自定义控件的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 FileVS.NET会帮你为每个没有Xml注释的public interface产生警告。这些警告有时多的烦人。如果你还没有准备好处理所有public interface的文档的话,你可以将Warning Level设置为2,这样,任务列表就不会收集警告信息,直到你将所有的事情都准备妥当之后,在将它设回来即可。

 

开始调试

现在我们有了一些可以调试的代码,让我们开始吧。为了调试我们的代码,我们需要步入(step into)容纳我们代码的应用程序中。在我们的示例中是VS.NET

 

设置调试属性

在调试过程中,我们需要改变一些调试属性。它们在VB.NETC#中有些许不同(译注:在此谨以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启动之后,打开相同的solutionC:\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 LaskerImmedient公司的National Director of Research & DevelopmentSteve曾经为Windows FormsASP.NET,和the .NET Compact Framework开发过一些.NET控件和框架。Steve的邮件地址是Steve.Lasker@Immedient.com


 

 

版权所有:UML软件工程组织