|
<p > <b>摘要</b>:本文讲解怎样建立动态属性来补充Visual Basic .NET已暴露的属性,以及使用动态属性保存应用程序实例间的用户配置。<p > <b>介绍</b><p >Visual Basic .NET中的动态属性提供了一条保存应用程序实例间属性设置的简单途径,它不需要借助注册表或者.ini文件。Visual Basic .NET在默认的情况下提供了大量的动态属性,你能够通过添加代码轻易的使其它属性变为动态的。<p > 例如,在默认的情况下,Windows Forms暴露了大量的动态属性,如MaximizeBox、MinimizeBox和ShowInTaskbar等等,但是没有暴露另外一些有用的属性,如Size或Location。<p > 动态属性保存在配置文件中,为了保存一个设置,配置文件必须修改。不可能要求终端用户在每次运行应用程序时修改配置文件。这样看来没有办法保存用户配置属性,例如窗体的最后的位置或者颜色。<p > 通过在应用程序中添加几行代码,你可以使任何属性象动态属性一样工作,使它可以被用户配置。本文将演示怎样设置动态属性,怎样使动态属性可以被用户配置,怎样建立新的动态属性。<p ><p > <b>动态属性是怎样工作的</b><p > 动态属性通过在应用程序配置文件(Windows应用程序中是app.config,Web应用程序中是web.config)中存储属性值来工作。当在属性窗体中添加一个动态属性时,将会有一个key/value对被添加到配置文件的appSettings段。此外,一个configurationAppSettings.GetValue调用被添加到InitializeComponent过程;该返回值被用于设置属性的初始值。当你编辑配置文件中的值时,你不需要更改InitializeComponent过程中的代码就能够改变初始属性值。<p > 例如Windows Form的TopMost属性决定一个窗体是否始终出现在其它窗体的顶层。通常你在设计时设置该属性,但是可以使应用程序更加灵活。通过把TopMost属性变为动态属性,你能在应用程序配置后听从选择。<p > <p > <b>学习动态属性如何工作</b><p > 1、建立一个叫DynamicProps的Windows应用程序并选中窗体设计器。<p > 2、在属性窗体中查找(DynamicProperties)节点并展开它,点击(Advanced)属性后面的省略按钮来打开Dynamic Properties对话框。<p > 3、在Properties列表中找到TopMost属性并选中它。<p > 注意Form1.TopMost默认值设置为Key mapping,但是你可以在这儿输入任意名称作为一个键,但是在我们的例子中还是使用这个默认值。<p > 4、在解决方案管理器中选择app.config文件并打开它。<p > <ccid_code>你应该看到<appSettings>段的<add key="Form1.TopMost:false" />行。该键与映射对话框的设置的默认键匹配,它的值是TopMost属性的默认值(false)。</ccid_code><p > 5、打开Form1的代码编辑器并展开标有Windows Form Designer generated code的段。在InitializeComponent过程中你可以看到下面的声明:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code>Dim configurationAppSettings As _ System.Configuration.AppSettingsReader = New System.Configuration.AppSettingsReader()</ccid_code></pre></td></tr></table></ccid_nobr><p > 这个声明建立了一个分析配置文件的AppSettingsReader类。<p > 该过程的下面代码是:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code>Me.TopMost = CType(configurationAppSettings.GetValue("Form1.TopMost", _ GetType(System.Boolean)), Boolean)</ccid_code></pre></td></tr></table></ccid_nobr><p > 这一行从配置文件中检索键Form1.TopMost,并把从配置文件中的Text数据转变为TopMost属性所要求的Boolean类型。<p > 6、运行该应用程序,可以看到窗体没有停留在顶层,关闭应用程序。<p > 7、打开app.config文件并把Form1.TopMost键的值改为true.<p > 8、重新运行该应用程序。<p > 这次窗体停留在顶层。如果你查看属性窗体的TopMost属性,会发现属性值改为true了。这是因为在属性和配置文件间有一个动态链接。<p > 下面将学习怎样在运行时使TopMost可以被用户配置。<p ><p > <b>保存用户配置的动态属性</b><p > 尽管修改配置文件改变动态属性很有用,但是如果用户可以配置属性将更加有用,这样用户可以从应用程序中改变动态属性。此外,应用程序应该在实例间保存和恢复设置。为了实现这个功能,你必须首先添加了一个用户界面来设置该属性。<p ><p > <b>为了保存用户可配置动态属性</b><p > 1、给窗体添加一个CheckBox控件,将它的Text属性设置为Stay on top。<p > 2、添加下面的CheckBox1_CheckedChanged事件处理程序代码:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code> rivate Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged Me.TopMost = CheckBox1.CheckedEnd Sub</ccid_code></pre></td></tr></table></ccid_nobr><p > 3、将该检查框的Checked属性改为true,这样该控件的值与TopMost属性的初始化设置匹配。<p > 4、运行应用程序<p > 当检查框被选中时,窗体停留在顶层,清除时,窗体没有停留在顶层。<p > 5、确认该检查框清除了并关闭应用程序。<p > 6、打开app.config文件可以发现TopMost属性的值仍为true。<p > 这使怎样发生的?尽管应用程序在初始化过程中能读入配置文件,但是当它们改变时没有办法自动地将值写入配置文件。你必须添加一些代码。<p > 你能够添加CheckedChanged事件处理程序代码,这样每次属性改变后,配置文件可以被更新。在应用程序关闭时简单地更新配置文件效率更高。<p > 7、在Form1_Closing事件处理程序中添加下面的代码:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code> rivate 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</ccid_code></pre></td></tr></table></ccid_nobr><p > 8、再次运行应用程序,清除检查框并关闭应用程序。<p > 9、打开app.config文件,Form1.TopMost的值变为false。<p > 如果你再次运行应用程序,窗体不再停留在顶层。<p > 为什么检查框仍然选中了?如果你测试窗体的行为,会发现它并不停留在顶层,因此该属性设置没有保存。问题是检查框的Checked属性没有同步。<p > 10、添加下面的Sub_New过程代码,紧跟在InitializeCompoment调用后面,来同步获取Checked属性。<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code> CheckBox1.Checked = Me.TopMost</ccid_code></pre></td></tr></table></ccid_nobr><p > 现在运行应用程序,检查框的状态正确的反映了TopMost行为。但还是有一个问题:如果选中了检查框,关闭并重新启动应用程序,检查框不再被选中。为什么?实际上有两个配置文件--在解决方案管理器中是app.config文件,在bin目录下面是appname.exe.config文件。如果你仔细查看代码,你会发现实际上将值保存在DynamicProps.exe.config文件中。你可以在解决方案管理器中点击Show All Files看到这个文件。<p > 每次应用程序建立时,app.config文件的内容复制到DynamicProps.exe.config文件,覆盖所有的改变。当应用程序展开时,DynamicProps.exe.config文件随着应用程序一起展开到应用程序的目录中。你可以直接写app.config文件,但是因为它停留在应用程序下面的层次,在展开后应用程序无法找到该文件。运行时为了应用那些改变,在应用程序再次运行前,你需要打开DynamicProps.exe.config并将内容复制到app.config文件。<p > 如果你要保存没有作为动态属性暴露的属性怎么办呢?下面将讲解怎样实现更多的动态属性。<p ><p > <b>建立新的动态属性</b><p > 作为暴露的默认动态属性的补充,你也许想保存其它的属性。例如,如果用户移动了窗体后我们想保存窗体的位置,这样窗体下次就可以在该位置打开。尽管窗体的Location属性没有作为动态属性暴露,你也可以修改app.config文件使它象动态属性一样工作。<p > <b>为了建立一个新动态属性</b><p > 1、在app.config文件的TopMost属性行下加入下面两行:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code><add key="Form1.X" value="0" /><add key="Form1.Y" value="0" /></ccid_code></pre></td></tr></table></ccid_nobr><p > 2、为了保存,关闭app.config文件,否则应用程序每次运行都会提示你。<p > 3、在过程的最后加上下面的代码,它将改变Sub_New事件处理程序从配置文件中读取值。<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code>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)</ccid_code></pre></td></tr></table></ccid_nobr><p > 请注意你建立了一个新的AppSettingsReader对象,因为在InitializeComponent过程中使用的对象不能访问。在配置文件中X和Y属性是分离的,因此你需要逐个设置。最后,Location属性使用Point对象作为参数,这样你就建立了一个指定了X和Y的相应的点。<p > 4、修改Form1_Closing事件处理程序来保存Location.X 和Location.Y到配置文件。添加下面的代码到行If Node.Name = "add" Then后面:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code>If Node.Attributes.GetNamedItem("key").Value = "Form1.X" Then ' 将X转化为字符串 Node.Attributes.GetNamedItem("value").Value = CType(Me.Location.X, String)End IfIf Node.Attributes.GetNamedItem("key").Value = "Form1.Y" Then Node.Attributes.GetNamedItem("value").Value = CType(Me.Location.Y,String)End If</ccid_code></pre></td></tr></table></ccid_nobr><p > 5、运行应用程序,移动窗体,接着关闭应用程序并重新启动它。<p > 窗体应该显示在原来的位置,但是没有。为什么呢?在初始化过程中,Location属性被StartPosition属性重载了,而StartPosition的默认值是WindowsDefault,这意味着Windows将决定窗体的初始位置。<p > 6、在过程再添加一个新行,这样属性设置才会实现:<p ><ccid_nobr><table width="550" border="1" cellspacing="0" cellpadding="2" bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"><tr><td bgcolor="f6f6f6" class="code"><pre><ccid_code>Me.StartPosition = FormStartPosition.Manual</ccid_code></pre></td></tr></table></ccid_nobr><p > 这次你运行并重新启动应用程序时,窗体就恢复到预计的先前的位置了。<p ><p > <b>结论</b><p > 如你所见,建立自己的动态属性并不困难,只需要在初始化和终止过程中加上几行代码。尽管本文讨论的是Windows应用程序,相同的技术可以简单地用于Web应用程序。<p ><center>(责任编辑 <ccid_nobr>西门吹雪</ccid_nobr>)</center><p align="center"></p></p> |
|