65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MSHTML 作为前端的 N 层应用程序

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (9投票s)

2004 年 1 月 14 日

9分钟阅读

viewsIcon

60440

N 层应用程序的描述。

引言

本文简要介绍了我使用 VB.NET 编写的一个多层应用程序。该应用程序有一个用途比较模糊的目的,即在一个名为 RSView32 的 SCADA 系统中提供电子签名。

然而,读者可能会感兴趣的是我如何配置应用程序的每个层,以及表示层如何托管 MSHTML。关于托管 MSHTML 的内容已经有很多,但大多数都依赖于 windows.external 调用来提供 MSHTML 窗格中的元素与应用程序之间的接口。我的应用程序采用了不同的方法,即使用一对一的关系,其中我的 .NET 表示对象托管 MSHTML 对象模型中的单个 DHTML 对象。

我必须为本文的粗略性质道歉,但我希望如果大家对此有很大的兴趣,我会进行大量的扩展。我没有包含屏幕截图,但可以在我网站上的软件描述中找到它们。

请记住,这些屏幕截图 **不是** 网页。MSHTML 窗格中的不同元素实际上连接到不同进程中的不同业务对象,并通过远程链接。当业务对象触发事件时,MSHTML 窗格的各个部分会被刷新,而不是整个窗格。

背景

表示层的想法源于一个我使用 Internet Explorer 制作原型的报告系统,其中当 HTML 元素展开时,它们会触发 Web 服务调用,使用 xslt 转换结果,然后将其插入 HTML 文档。我发现使用 JavaScript 很难处理复杂性,并开始思考如何将 .NET 代码嵌入 Internet Explorer 网页中,使其“实时”。一旦我发现我可以通过编程方式访问 MSHTML 页面的整个对象模型,我就意识到解决方案是将该模型中的 DHTML 对象嵌入到 .NET 应用程序中。

描述

dkTagSet 是一套程序,为 RSView32 SCADA 系统提供嵌入式电子签名和显示的文档。

dkTagSet 用于使用户能够从 SCADA 系统设置标签。当用户选择设置或编辑标签时,会弹出一个屏幕,向用户显示文档,并要求用户输入多个电子签名。一旦添加了这些签名,就设置了所需的标签。

dkTagSet 向用户显示有关正在设置的标签的详细信息,包括 PLC 地址和标签描述。

在 RSView32 项目中配置后,用户可以从运行时环境中重新配置签名,而无需重新编辑屏幕。此重新配置包括配置用户显示的文档以及为该操作所需的确认。所有重新配置均受电子签名保护,所有重新配置操作都可以关联文档。

dkTagSet 维护其执行的所有操作的完整审计跟踪。此审计跟踪包括标签设置操作和系统重新配置。审计跟踪可以从前端查看。

架构

dkTagSet 采用多层架构。多层应用程序被划分为多个单独的层,每一层执行不同类别的功能。dkTagSet 分为以下几层:

数据层

数据层包含一个 SQL Server 数据库。系统执行的所有操作都记录在此数据库的一组表中。它具有由数据访问层调用的简单存储过程来插入和更新数据。该架构允许使用不同的数据库。

数据访问层

数据访问层是用 .NET Framework 编写的一组类。

它使用专有驱动程序与 SQL Server 数据库通信,尽管实际上该驱动程序已配置为可以使用其他数据库。

数据层由 XML 配置文件配置,该文件定义了多个不同的数据访问对象。当从数据层请求具有特定名称的数据访问对象时,它使用此 XML 文件查找并配置所需对象。XML 配置文件配置以下内容:

  • 对象的 .NET 类型和程序集
  • 定义用于与对象进行通信的数据集结构的 XML 架构
  • 用于连接到数据库的驱动程序
  • 用于从数据库读取数据和写入数据的规则

使用标准接口与所有数据访问对象进行通信。此接口使用 DataSets。

当需要数据访问对象的数据时,数据集定义了所需的数据。数据访问对象使用其配置的规则生成查询以从数据库获取数据,然后以数据集的形式返回数据。

当需要数据对象将数据写入数据库时,要写入的数据以数据集的形式传递给它。数据对象使用为其配置的规则将此数据写回数据库。

数据层配置示例

此 XML 元素配置了一个数据访问对象(在本例中为一组确认的数据)

    <confirmations>
     <dalObject 
type='dkcs.dal.dalConfirmations.dkConfirmationsDataObject' 
   assemblyFile='dal.dll'>
      <schema path='schemas/schemaConfirmations.xsd' />
      <getDataSet>
       <table name="confirmations">
        <table name="confirmation" 
queryString="select * from confirmation where (1=0) " 
   order='  order by ord asc'>
         <linkFields parentTableName="confirmations">
          <linkField name="parentGuid" 
  parentFieldName="guid" type='string' />
         </linkFields>
        </table>
       </table>
       <dataSet queryString=
   "select * from confirmations where (1 = 9) ">
        <or>
         <table tableName='confirmations' operator='or'>
          <selector leftField='parentGuid' conJoin='=' 
    tableField='parentGuid' type='string' />
          <selector operator='or' leftField='guid' conJoin='=' 
   tableField='guid' type='string' />
         </table>
        </or>
       </dataSet>
      </getDataSet>
      <storeDataset>
       <update tableName='confirmations'>
        <insertCommand commandText='insertConfirmations'>
         <parameter dbType='16' 
  parameterName="@parentGuid" sourceColumn='parentGuid' />
         <parameter dbType='16' 
  parameterName="@guid" sourceColumn='guid' />
         <parameter dbType='16' 
  parameterName="@confirmSet" sourceColumn='confirmSet' />
         <parameter dbType='16' 
  parameterName="@zone" sourceColumn='zone' />
         <parameter dbType='16' 
  parameterName="@dalObject" sourceColumn='dalObject' />
         <parameter dbType='6' 
  parameterName="@dateCreated" sourceColumn='dateCreated' />
        </insertCommand>
        <updateCommand commandText='updateConfirmations'>
         <parameter dbType='16' 
  parameterName="@parentGuid" sourceColumn='parentGuid' />
         <parameter dbType='16' 
  parameterName="@guid" sourceColumn='guid' />
         <parameter dbType='16' 
  parameterName="@confirmSet" sourceColumn='confirmSet' />
         <parameter dbType='16' 
  parameterName="@zone" sourceColumn='zone' />
         <parameter dbType='16' 
  parameterName="@dalObject" sourceColumn='dalObject' />
         <parameter dbType='16' 
  parameterName="@confirmResult" 
    sourceColumn='confirmResult' />
         <parameter dbType='6' 
  parameterName="@dateConfirmed" 
    sourceColumn='dateConfirmed' />
        </updateCommand>
       </update>
       <update tableName='confirmation'>
        <insertCommand commandText='insertConfirmation'>
         <parameter dbType='16' 
  parameterName="@parentGuid" sourceColumn='parentGuid' />
         <parameter dbType='16' 
  parameterName="@guid" sourceColumn='guid' />
         <parameter dbType='10' 
  parameterName="@ord" sourceColumn='ord' />
         <parameter dbType='16' 
  parameterName="@confirmType" sourceColumn='confirmType' />
         <parameter dbType='16' 
  parameterName="@attemptGuid" sourceColumn='attemptGuid' />
        </insertCommand>
        <updateCommand commandText='updateConfirmation'>
         <parameter dbType='16' 
  parameterName="@guid" sourceColumn='guid' />
         <parameter dbType='16' 
  parameterName="@attemptGuid" sourceColumn='attemptGuid' />
         <parameter dbType='16' 
  parameterName="@failGuid" sourceColumn='failGuid' />
        </updateCommand>
       </update>
      </storeDataset>
      <configuration>
       <confirmSets 
  xmlns="http://www.dkcs.ws/dk400/namespaces/confirmations">
        <confirmations confirmSet="defaultConfirm">
         <confirmation ord='1' confirmType="operatorConfirm" />
        </confirmations>
        <confirmations confirmSet="operatorConfirm">
         <confirmation ord='1' confirmType="operatorConfirm" />
        </confirmations>
        <confirmations confirmSet="controllerConfirm">
         <confirmation ord='1' confirmType="controllerConfirm" />
        </confirmations>
        <confirmations confirmSet="no id required">
         <confirmation ord='1' confirmType="no id required" />
        </confirmations>
        <confirmations confirmSet="doubleOperatorConfirm">
         <confirmation ord='1' confirmType="operatorConfirm" />
         <confirmation ord='2' confirmType="operatorConfirm" />
        </confirmations>
        <confirmations confirmSet="administratorConfirm">
         <confirmation ord='1' confirmType="administratorConfirm" />
        </confirmations>
       </confirmSets>
      </configuration>
     </dalObject>
    </confirmations>

数据对象接口

所有数据对象都符合以下接口。业务层不知道也不知道如何区分它正在实际与之通信的数据对象。

Public Interface dkIDataObject

Inherits general.general.dkIObject

'this interface is shared by all data access objects

'it defines methods to retrieve and store data

' get a dataset sppoecified by the querydataset

Overloads Function getDataSet(ByVal queryDataset _
  As DataSet) As DataSet

' get a dataset as specified by the query string

'Overloads Function getDataset(ByVal queryString _
  As String) As DataSet

'store the dataset in the datasource

Sub storeDataSet(ByVal storeDataset As DataSet)

'return a new blank dataset

Function blankDataSet() As DataSet

'initialise an initial dataset

Function initDataSet() As DataSet

'update a dataset by adding the tables and relations 
'for thew data access object

Function updateDataset(ByVal ds As DataSet) As DataSet



Overloads Function create(ByVal createDataSet As _
  DataSet) As DataSet

End Interface

数据工厂

这是数据对象的工厂,它创建一个对象,对其进行配置,然后为客户端对象调用其上的函数。

Imports System.EnterpriseServices

Imports System.Xml.Serialization

Imports dkcs.dal.dalConfigurable

Imports dkcs.dal.dalGeneral

Imports dkcs.general.general

Namespace dal.dalFactory

<Serializable()> _

Public Class dkDataFactoryConfigurable

'Inherits dkcs.dal.base.dkDataObject

Inherits servicedConfigurator

Implements dkIDataObjectFactory

'this class is a factory class that makes data 
'access layer objects


Public Sub New()

MyBase.new()


End Sub



Private Function getDataObject(ByVal zone As String, _
  ByVal name As String) As dkIDataObject

'return a data object configured with the configuration



Dim c As New dalbase.dkDataObjectConfigurable()

c.configuration = dkZoneConfiguration.zoneConfiguration( _
  zone).SelectSingleNode("dalObjects").SelectSingleNode(name)

Return c

End Function

业务层

业务层是用 .NET Framework 编写的一组类。所有类都有一个公共接口,允许使用 .NET DataSets 与对象进行通信。这些类还能够持有其他业务对象并在请求时返回这些业务对象。

业务层由 XML 配置文件配置,该文件定义了多个不同的业务对象。当从业务层请求具有特定名称的业务对象时,它使用此 XML 文件查找并配置所需对象。XML 配置文件为每个业务对象配置以下内容:

  • 对象的 .NET 类型和程序集
  • 各种“子对象”的名称和网络位置,这些子对象是其他业务对象以及数据访问对象
  • 特定于对象的其他配置信息

业务层配置示例

此 XML 元素配置了一个业务层对象(在本例中为一组确认),dal 对象的 url 可以使其位于不同的机器上。

  <confirmations>  
     <businessObject 
  type='dkcs.business.confirmations.confirmationsBusinessObject' 
  assemblyFile='business.dll' zone="xBrewery">
     
      <objectUrls>
      
       <objectUrl purpose='dal'  
  url='tcp://:123/dalFactory.soap' 
  name='confirmations' />      
       <objectUrl purpose='businessSecurityProviderFactory' 
      url='' name='securityProvider' />
     </objectUrls>  
     </businessObject>
    </confirmations>

业务层接口

此接口由所有业务对象实现,使用业务层对象的对象实际上不知道它们正在使用的对象的类型。

Public Interface dkIBusinessObject

Inherits dkcs.general.general.dkIObject

Inherits dkcs.general.general.dkIConfigurable

Inherits IDisposable

Property initDataset() As DataSet 'sets the initial 
'dataset for the object

Property initDataSetString() As String

Function getDataSet() As DataSet 'gets the dataset 
'contained by the object

Function getDataSet(ByVal parentDataSet As DataSet, _
  ByVal tableName As String) As DataSet

Function setDataSet(ByVal ds As DataSet) _
  As DataSet 'used to command the object

Function setDataSet(ByVal ds As DataSet, _
   ByVal objectName As String) As DataSet

Function blankdataset() As DataSet 'returns a blank 
'dataset with required structure

Sub storedataset() 'requests the object to store its dataset

Event changeDataset(ByVal ds As DataSet) 'event raised 
'when dataset changes (would not work for remote objects)

Function getBusinessObject(ByVal name As String, _
  ByVal parentDataSet As DataSet) As dkIBusinessObject 
  'gets a contained business object

Function setBusinessObject(ByVal name As String, _
  ByVal businessObject As dkIBusinessObject) As dkIBusinessObject 
  'sets a business object - used to pass other business 
  'objects into thos one

Property businessFactory() As dkIBusinessFactory 
  'the business factory that created me

ReadOnly Property key()

Function command(ByVal ParamArray commandstring() _
  As String) As String 'command

ReadOnly Property businessObject() As dkIBusinessObject 
  'returns me or my nbusiness object if I am a factory

End Interface

业务工厂

这是处理创建业务对象的命名空间。业务工厂伪装成它创建的业务对象。

' ## This namespace deals with creating business objects

Public Class myBusinessFactory

' Creates a business object as of the indicated name 
' as defined in the configuration

Shared Function getBusinessObject(ByVal configuration _
  As Xml.XmlElement, ByVal objectName As String, _
  ByVal parentDataSet As DataSet) As dkIBusinessObject

Dim o As Object = getBusinessFactory(configuration, _
  objectName).getBusinessObject(configuration.SelectSingleNode( _
  String.Format("objectUrls/objectUrl[@purpose='{0}']/@name", _
  objectName)).Value, parentDataSet)

Return o

End Function

Overloads Shared Function getBusinessFactory(ByVal configuration _
  As Xml.XmlElement, ByVal objectName As String) As _
  general.dkIBusinessFactory



Dim n As Xml.XmlNode = configuration.SelectSingleNode( _
  String.Format("objectUrls/objectUrl[@purpose='{0}']/@url", _
  objectName))

If Not n Is Nothing Then

Dim b As dkIBusinessFactory = getBusinessFactory( _
  configuration.Attributes("zone").Value, n.Value)



b.name = configuration.SelectSingleNode(String.Format( _
  "objectUrls/objectUrl[@purpose='{0}']/@name", _
  objectName)).Value

Return b

End If


End Function

Overloads Shared Function getBusinessFactory( _
  ByVal zone As String, ByVal url As String) _
  As general.dkIBusinessFactory

'gets a business factory



Dim fact1 As dkcs.business.general.dkIBusinessFactory

If url = "" Then

fact1 = New dkBusinessFactoryConfigurable()

Else



Dim args() As Object

' Uses the UrlAttribute to create a remote object.

Dim activationAttributes() = {New UrlAttribute(url)}

' Activates an object for this client.

Dim hdlSample As ObjectHandle

'hdlSample = Activator.CreateInstance("businessFactory", _
  "dkcs.business.factory.dkBusinessFactoryConfigurable", _
  True, BindingFlags.Instance Or BindingFlags.Public, Nothing, _
  args, Nothing, activationAttributes, Nothing)

hdlSample = Activator.CreateInstance("businessFactory", _
  "dkcs.business.factory.dkBusinessFactoryConfigurable", _
  True, BindingFlags.Instance Or BindingFlags.Public, Nothing, _
   args, Nothing, activationAttributes, Nothing)

fact1 = CType(hdlSample.Unwrap(), dkBusinessFactoryConfigurable)

fact1.zone = zone

End If

fact1.zone = zone


Return fact1

End Function

End Class

Public Class dkBusinessFactoryHost

Inherits dkBusinessFactoryConfigurable

Dim WithEvents hostedObject As dkIBusinessObject

Public Sub New(ByVal myobject As dkIBusinessObject)

Me.myobject = myobject

End Sub

Public Sub doit(ByVal ds As DataSet)

domessagearrival(ds)

End Sub

Private Sub hostedObject_changeDataset(ByVal ds As _
  System.Data.DataSet) Handles hostedObject.changeDataset

domessagearrival(ds)

End Sub

End Class

'this class builds and allows interface to a business object

<Serializable()> _

Public Class dkBusinessFactoryConfigurable

Inherits dkcs.general.general.nonServicedconfigurator

Implements dkIBusinessFactory

Dim mvarname As String

Dim mvarZone As String

'this is the object I have built

Protected WithEvents myobject As _
  dkcs.business.general.dkIBusinessObject

Public Sub New()

MyBase.new()

End Sub

Public Property zone() As String _
  Implements dkIBusinessFactory.zone

Get

Return mvarZone

End Get

Set(ByVal Value As String)



mvarZone = Value

'the configuration of business objects for this zone

Me.configuration = dkZoneConfiguration.zoneConfiguration( _
  Value).SelectSingleNode("businessObjects")



End Set

End Property

'when I am given a name I create a business object as 
'defined in configuration and listen to it

Public Property name() As String Implements _
  dkIBusinessFactory.name

Get

Return (mvarname)

End Get

Set(ByVal Value As String)

mvarname = Value

If Value <> "" Then

myobject = getBusinessObject(name, New DataSet())

myobject.businessFactory = Me

Me.listenToBroadcaster(myobject)

End If

End Set

End Property



'return my business object

Public ReadOnly Property businessobject() As _
  dkcs.business.general.dkIBusinessObject Implements _
  dkIBusinessFactory.businessObject

Get

Return myobject

End Get

End Property



'pass call to contained business object

Public Function blankdataset() As System.Data.DataSet _
  Implements dkcs.business.general.dkIBusinessFactory.blankdataset

Return myobject.blankdataset

End Function



'pass call to contained business object

Public Overloads Function getDataSet() As System.Data.DataSet _
  Implements dkcs.business.general.dkIBusinessFactory.getDataSet

'

Return myobject.getDataSet

End Function



'pass call to contained business object

Public Overloads Function setDataSet(ByVal ds As _
  System.Data.DataSet) As System.Data.DataSet Implements _
  dkcs.business.general.dkIBusinessFactory.setDataSet

Return myobject.setDataSet(ds)

End Function

Public ReadOnly Property key() As Object Implements _
  dkcs.business.general.dkIBusinessFactory.key

Get

Return name

End Get

End Property

'pass call to contained business object

Public Property initDataset() As System.Data.DataSet _
  Implements dkcs.business.general.dkIBusinessFactory.initDataset

Get

'

Return myobject.initDataset

End Get

Set(ByVal Value As System.Data.DataSet)

myobject.initDataset = Value

End Set

End Property

Public Event changeDataset(ByVal ds As System.Data.DataSet) _
  Implements dkcs.business.general.dkIBusinessFactory.changeDataset



'pass call to contained business object

Public Property businessFactory() As _
  dkcs.business.general.dkIBusinessFactory Implements _
  dkcs.business.general.dkIBusinessFactory.businessFactory

Get

Return Me

End Get

Set(ByVal Value As dkcs.business.general.dkIBusinessFactory)

Throw New Exception( _
  "cannot set a business factory's businessfactory")

End Set

End Property

'pass call to contained business object

Public Overloads Function getDataSet(ByVal parentDataSet As _
  System.Data.DataSet, ByVal tableName As String) As _
  System.Data.DataSet Implements _
  dkcs.business.general.dkIBusinessFactory.getDataSet

Dim ds As DataSet = myobject.getDataSet(parentDataSet, tableName)



Return ds

End Function

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then myobject.Dispose()

MyBase.Dispose(disposing)

End Sub

'pass call to contained business object

Public Property initDataSetString() As String Implements _
  dkcs.business.general.dkIBusinessFactory.initDataSetString

Get

Return myobject.initDataSetString

End Get

Set(ByVal Value As String)

myobject.initDataSetString = Value

End Set

End Property

'pass call to contained business object

Public Sub storedataset() Implements _
  dkcs.business.general.dkIBusinessFactory.storedataset

myobject.storedataset()

End Sub



 

'returns a business object specified by name - 
'nb does nothing with parent dataset

Public Function getBusinessObject(ByVal name As String, _
  ByVal parentDataSet As System.Data.DataSet) As _
  dkcs.business.general.dkIBusinessObject Implements _
  dkcs.business.general.dkIBusinessFactory.getBusinessObject

If Not configuration.SelectSingleNode(name) Is Nothing Then

'merge n with any external files

Dim n As Xml.XmlElement = _
  dkcs.general.general.xmlMerge.externalCheck( _
  configuration.SelectSingleNode(name))

'create and configure object

Dim bo As dkcs.business.general.dkIBusinessObject = _
  dkcs.general.general.objectFactory.getConfiguredObject( _
  configuration.SelectSingleNode(name).SelectSingleNode( _
  "businessObject"))



Return bo

End If

End Function

'pass call to contained business object

Public Overloads Function setDataSet(ByVal ds As _
  System.Data.DataSet, ByVal objectName As String) As _ 
  System.Data.DataSet Implements _
  dkcs.business.general.dkIBusinessFactory.setDataSet

Return myobject.setDataSet(ds, objectName)

End Function

'pass call to contained business object

Public Overloads Function command(ByVal ParamArray commandstring() _
  As String) As String Implements _
  dkcs.business.general.dkIBusinessFactory.command

Return Me.businessobject.command(commandstring)

End Function

'pass call to contained business object

Public Function setBusinessObject(ByVal name As String, _
  ByVal businessObject As dkcs.business.general.dkIBusinessObject) _
  As dkIBusinessObject Implements _
  dkcs.business.general.dkIBusinessFactory.setBusinessObject

Return Me.businessobject.setBusinessObject(name, businessObject)

End Function



End Class

表示层

表示层是用 .NET Framework 编写的一组类。表示层中的对象形成一个复杂的层次结构,取决于表示层的配置和业务层的结构。表示对象能够持有对业务层中业务对象的引用,并请求那些业务层对象的“子对象”,并生成持有那些业务层对象的嵌套对象。

当业务层对象引发事件时,表示层对象会接收到这些事件,然后根据接收到的新数据更新其内容。

表示层对象能够通过发送数据集来请求业务层对象的功能。

表示层对象能够拥有多个“行为”。行为控制表示对象如何实际呈现给用户。这使得表示对象本身独立于表示技术。

目前使用的“行为”持有对 MSHTML 对象模型中 DHTML 对象的引用。MSHTML 是 Internet Explorer 用于向用户呈现 HTML 内容的 COM 控件。每个 DHTML 控件都是 MSHTML 呈现的 HTML 中的一个元素。表示控件直接操作其托管的 DHTML 控件的属性,并响应其引发的事件。这使得页面“实时”,不同的部分在不同的网络和进程位置响应不同的业务对象。当表示控件本身包含其他表示控件时,这些包含的表示控件所托管的 DHTML 控件本身就包含在父表示对象托管的 DHTML 控件中。这种架构与网页不同,网页通常连接到单个服务器,更新时需要刷新整个页面,并且不响应服务器引发的事件。

表示层配置在一组 XML 文件中。每个表示对象都在这些文件中进行配置。这些文件配置显示根对象的名称和位置,然后是控件的层次结构。如果它连接到实现标准业务层接口的业务层,那么相同的表示层可以配置为连接到完全不同的业务层,具有不同的功能。

表示层的 XML 文件配置了多个不同的表示层控件的类型以及其行为的类型。然后在表示层控件的层次结构中,它为每个表示控件配置:

  • 如何获取其业务对象(如果它获取新的对象)
  • 来自业务对象的用于显示的数据的 XPath
  • 其托管对象的属性(对于 DHTML 对象,这将是 HTML 属性(class 等))
  • 包含在控件中的表示控件
  • 控件展开时生成的表示控件。
  • 通过右键单击元素可用的菜单选项

表示配置中的元素可以引用外部文件,其内容将与其合并。

表示层配置示例

此 XML(及其引用的外部文件)配置了确认的显示方式。

<listedControl function='expander'>

 <menuControls />
 
 <containedControls> 
 
  <dkXmlAttributeControl function='label' 
dkKey='authorisationLabel' attributeName="@confirmSet">
   
   <configurator>
    
    <oneOffs>
     
     <htmlAttributes>
      <class>authorisation</class>
   
      <style>width:20%</style>    
    
     </htmlAttributes>   
   
    </oneOffs>  
  
   </configurator> 
 
  </dkXmlAttributeControl>
 
 </containedControls>

 <subControls>
  <listingControl function='list' 
  xpath="confirmations:confirmation" 
  keyAttribute="guid" childIndex='99'>
   <listedControl function='expander'>    
   
    <configurator>
     
    
     <oneOffs>
      
     
      <expanded>true</expanded>
    
     </oneOffs>   
   
    </configurator>    
   
    <containedControls>     
    
     <dkXmlAttributeControl function='label' 
  attributeName="@confirmType" dkKey='confirmType'>
      
     
      <configurator>
       
      
       <oneOffs>
        
       
        <htmlAttributes>
         
        
         <width>10%</width>
        
         <class>confirmation</class>
       
        </htmlAttributes>
       
      
       </oneOffs>
      
     
      </configurator>
     
    
     </dkXmlAttributeControl>
    
   
    </containedControls>
    
   
    <subControls>
     
    
     <listingControl function='list' 
  xpath="confirmations:confirmationAttempt[@confirmationResult]/.."
      keyAttribute="" childIndex='1' dkKey='failedAttempts'>
      
     
      <listedControl function='expander'>
       
      
       <configurator>
        
       
        <oneOffs></oneOffs>
       
      
       </configurator>
       
      
       <containedControls>
        
       
        <dkXmlAttributeControl function='label' dkKey='error'>         
        
         <configurator>
          
         
          <oneOffs>
           
          
           <prefix>failed Attempts</prefix>          
           <htmlAttributes>
            
           
            <class>error</class>
          
           </htmlAttributes>
          
         
          </oneOffs>
         
        
         </configurator>
        
       
        </dkXmlAttributeControl>
       
      
       </containedControls>
       
      
       <subControls>
        
       
        <listingControl function='list' 
  xpath="confirmations:confirmationAttempt[@confirmationResult]" 
  keyAttribute="guid">
         
        
         <listedControl function='expander' 
  externalFilePath='confirmationAttempt.xml' />
        
       
        </listingControl>
       
      
       </subControls>
      
     
      </listedControl>
     
    
     </listingControl>
     
    
     <listingControl function='list' 
  xpath="confirmations:confirmationAttempt[not (@confirmationResult)]"
      keyAttribute="guid" 
  externalFilePath='confirmationAttempt.xml' dkKey='confirmationAttempt'>
      
     
      <listedControl function='expander' 
externalFilePath='confirmationAttempt.xml' />
     
    
     </listingControl>
    
   
    </subControls>
   
  
   </listedControl>
  
 
  </listingControl>
 </subControls>
</listedControl>

关注点

我在 MSHTML 对象模型方面遇到了一些困难,并且还没有解决所有问题。例如,我从未成功接收到单个对象的按键事件。我期待新的 webbrowser 控件,并想知道 Microsoft 是否已经尽力解决了对模型中所有 DHTML 对象的访问。

历史

  • 到目前为止没有变化
© . All rights reserved.