UML软件工程组织

VB.NET中建立动态属性和保存属性设置
作者:陶刚 本文选自:赛迪网 2003年04月14日

 

摘要:本文讲解怎样建立动态属性来补充Visual Basic .NET已暴露的属性,以及使用动态属性保存应用程序实例间的用户配置。

介绍

Visual Basic .NET中的动态属性提供了一条保存应用程序实例间属性设置的简单途径,它不需要借助注册表或者.ini文件。Visual Basic .NET在默认的情况下提供了大量的动态属性,你能够通过添加代码轻易的使其它属性变为动态的。

例如,在默认的情况下,Windows Forms暴露了大量的动态属性,如MaximizeBox、MinimizeBox和ShowInTaskbar等等,但是没有暴露另外一些有用的属性,如Size或Location。

动态属性保存在配置文件中,为了保存一个设置,配置文件必须修改。不可能要求终端用户在每次运行应用程序时修改配置文件。这样看来没有办法保存用户配置属性,例如窗体的最后的位置或者颜色。

通过在应用程序中添加几行代码,你可以使任何属性象动态属性一样工作,使它可以被用户配置。本文将演示怎样设置动态属性,怎样使动态属性可以被用户配置,怎样建立新的动态属性。

动态属性是怎样工作的

动态属性通过在应用程序配置文件(Windows应用程序中是app.config,Web应用程序中是web.config)中存储属性值来工作。当在属性窗体中添加一个动态属性时,将会有一个key/value对被添加到配置文件的appSettings段。此外,一个configurationAppSettings.GetValue调用被添加到InitializeComponent过程;该返回值被用于设置属性的初始值。当你编辑配置文件中的值时,你不需要更改InitializeComponent过程中的代码就能够改变初始属性值。

例如Windows Form的TopMost属性决定一个窗体是否始终出现在其它窗体的顶层。通常你在设计时设置该属性,但是可以使应用程序更加灵活。通过把TopMost属性变为动态属性,你能在应用程序配置后听从选择。

学习动态属性如何工作

1、建立一个叫DynamicProps的Windows应用程序并选中窗体设计器。

2、在属性窗体中查找(DynamicProperties)节点并展开它,点击(Advanced)属性后面的省略按钮来打开Dynamic Properties对话框。

3、在Properties列表中找到TopMost属性并选中它。

注意Form1.TopMost默认值设置为Key mapping,但是你可以在这儿输入任意名称作为一个键,但是在我们的例子中还是使用这个默认值。

4、在解决方案管理器中选择app.config文件并打开它。

你应该看到<appSettings>段的<add key="Form1.TopMost:false" />行。该键与映射对话框的设置的默认键匹配,它的值是TopMost属性的默认值(false)。

5、打开Form1的代码编辑器并展开标有Windows Form Designer generated code的段。在InitializeComponent过程中你可以看到下面的声明:

Dim configurationAppSettings As _
System.Configuration.AppSettingsReader = New System.Configuration.AppSettingsReader()

这个声明建立了一个分析配置文件的AppSettingsReader类。

该过程的下面代码是:

Me.TopMost = CType(configurationAppSettings.GetValue("Form1.TopMost", _
GetType(System.Boolean)), Boolean)

这一行从配置文件中检索键Form1.TopMost,并把从配置文件中的Text数据转变为TopMost属性所要求的Boolean类型。

6、运行该应用程序,可以看到窗体没有停留在顶层,关闭应用程序。

7、打开app.config文件并把Form1.TopMost键的值改为true.

8、重新运行该应用程序。

这次窗体停留在顶层。如果你查看属性窗体的TopMost属性,会发现属性值改为true了。这是因为在属性和配置文件间有一个动态链接。

下面将学习怎样在运行时使TopMost可以被用户配置。

保存用户配置的动态属性

尽管修改配置文件改变动态属性很有用,但是如果用户可以配置属性将更加有用,这样用户可以从应用程序中改变动态属性。此外,应用程序应该在实例间保存和恢复设置。为了实现这个功能,你必须首先添加了一个用户界面来设置该属性。

为了保存用户可配置动态属性

1、给窗体添加一个CheckBox控件,将它的Text属性设置为Stay on top。

2、添加下面的CheckBox1_CheckedChanged事件处理程序代码:

Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
Me.TopMost = CheckBox1.Checked
End Sub

3、将该检查框的Checked属性改为true,这样该控件的值与TopMost属性的初始化设置匹配。

4、运行应用程序

当检查框被选中时,窗体停留在顶层,清除时,窗体没有停留在顶层。

5、确认该检查框清除了并关闭应用程序。

6、打开app.config文件可以发现TopMost属性的值仍为true。

这使怎样发生的?尽管应用程序在初始化过程中能读入配置文件,但是当它们改变时没有办法自动地将值写入配置文件。你必须添加一些代码。

你能够添加CheckedChanged事件处理程序代码,这样每次属性改变后,配置文件可以被更新。在应用程序关闭时简单地更新配置文件效率更高。

7、在Form1_Closing事件处理程序中添加下面的代码:

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As _
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
' 使用反射查找配置文件中的位置
Dim Asm As System.Reflection.Assembly = _
System.Reflection.Assembly.GetExecutingAssembly
Dim strConfigLoc As String
strConfigLoc = Asm.Location

'配置文件再应用程序的bin目录,因此需要删除文件名
Dim strTemp As String
strTemp = strConfigLoc
strTemp = System.IO.Path.GetDirectoryName(strConfigLoc)

'为配置文件定义一个FileInfo对象
Dim FileInfo As System.IO.FileInfo = New _
System.IO.FileInfo(strTemp & "\DynamicProps.exe.config")

'将配置文件读入XML DOM
Dim XmlDocument As New System.Xml.XmlDocument()
XmlDocument.Load(FileInfo.FullName)

'找到正确的节点并将它的值改为新的
Dim Node As System.Xml.XmlNode
For Each Node In XmlDocument.Item("configuration").Item("appSettings")
'略过注释
If Node.Name = "add" Then
If Node.Attributes.GetNamedItem("key").Value = "Form1.TopMost" Then
Node.Attributes.GetNamedItem("value").Value = CType(Me.TopMost, String)
End If
End If
Next Node

'保存修改过的配置文件
XmlDocument.Save(FileInfo.FullName)
End Sub

8、再次运行应用程序,清除检查框并关闭应用程序。

9、打开app.config文件,Form1.TopMost的值变为false。

如果你再次运行应用程序,窗体不再停留在顶层。

为什么检查框仍然选中了?如果你测试窗体的行为,会发现它并不停留在顶层,因此该属性设置没有保存。问题是检查框的Checked属性没有同步。

10、添加下面的Sub_New过程代码,紧跟在InitializeCompoment调用后面,来同步获取Checked属性。

CheckBox1.Checked = Me.TopMost

现在运行应用程序,检查框的状态正确的反映了TopMost行为。但还是有一个问题:如果选中了检查框,关闭并重新启动应用程序,检查框不再被选中。为什么?实际上有两个配置文件--在解决方案管理器中是app.config文件,在bin目录下面是appname.exe.config文件。如果你仔细查看代码,你会发现实际上将值保存在DynamicProps.exe.config文件中。你可以在解决方案管理器中点击Show All Files看到这个文件。

每次应用程序建立时,app.config文件的内容复制到DynamicProps.exe.config文件,覆盖所有的改变。当应用程序展开时,DynamicProps.exe.config文件随着应用程序一起展开到应用程序的目录中。你可以直接写app.config文件,但是因为它停留在应用程序下面的层次,在展开后应用程序无法找到该文件。运行时为了应用那些改变,在应用程序再次运行前,你需要打开DynamicProps.exe.config并将内容复制到app.config文件。

如果你要保存没有作为动态属性暴露的属性怎么办呢?下面将讲解怎样实现更多的动态属性。

建立新的动态属性

作为暴露的默认动态属性的补充,你也许想保存其它的属性。例如,如果用户移动了窗体后我们想保存窗体的位置,这样窗体下次就可以在该位置打开。尽管窗体的Location属性没有作为动态属性暴露,你也可以修改app.config文件使它象动态属性一样工作。

为了建立一个新动态属性

1、在app.config文件的TopMost属性行下加入下面两行:

<add key="Form1.X" value="0" />
<add key="Form1.Y" value="0" />

2、为了保存,关闭app.config文件,否则应用程序每次运行都会提示你。

3、在过程的最后加上下面的代码,它将改变Sub_New事件处理程序从配置文件中读取值。

Dim configReader As System.Configuration.AppSettingsReader = New _
System.Configuration.AppSettingsReader()
Dim x As Integer, y As Integer
' 从配置文件中检索值并转化为整型
x = CType(configReader.GetValue("Form1.X", GetType(System.Int32)), Integer)
y = CType(configReader.GetValue("Form1.Y", GetType(System.Int32)), Integer)
' 使用新的x和y设置位置
Me.Location = New System.Drawing.Point(x, y)

请注意你建立了一个新的AppSettingsReader对象,因为在InitializeComponent过程中使用的对象不能访问。在配置文件中X和Y属性是分离的,因此你需要逐个设置。最后,Location属性使用Point对象作为参数,这样你就建立了一个指定了X和Y的相应的点。

4、修改Form1_Closing事件处理程序来保存Location.X 和Location.Y到配置文件。添加下面的代码到行If Node.Name = "add" Then后面:

If Node.Attributes.GetNamedItem("key").Value = "Form1.X" Then
' 将X转化为字符串
Node.Attributes.GetNamedItem("value").Value = CType(Me.Location.X, String)
End If
If Node.Attributes.GetNamedItem("key").Value = "Form1.Y" Then
Node.Attributes.GetNamedItem("value").Value = CType(Me.Location.Y,String)
End If

5、运行应用程序,移动窗体,接着关闭应用程序并重新启动它。

窗体应该显示在原来的位置,但是没有。为什么呢?在初始化过程中,Location属性被StartPosition属性重载了,而StartPosition的默认值是WindowsDefault,这意味着Windows将决定窗体的初始位置。

6、在过程再添加一个新行,这样属性设置才会实现:

Me.StartPosition = FormStartPosition.Manual

这次你运行并重新启动应用程序时,窗体就恢复到预计的先前的位置了。

结论

如你所见,建立自己的动态属性并不困难,只需要在初始化和终止过程中加上几行代码。尽管本文讨论的是Windows应用程序,相同的技术可以简单地用于Web应用程序。




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