LzmTW.uSystem.uCollection.SinceLink

Author:水如烟  

 

Namespace  LzmTW.uSystem.uCollection
    
' '' <summary>
     ' '' 树节点
     ' '' </summary>
     ' '' <remarks>LzmTW 20061111</remarks>
     < Serializable() >  _
    
Public   Class  Node( Of  T)

        
Friend  gIsRoot  As   Boolean   =   True
        
Friend  gParent  As  Node( Of  T)

        
' '' <summary>
         ' '' 当前节点的父节点
         ' '' </summary>
         Public   ReadOnly   Property  Parent()  As  Node( Of  T)
            
Get
                
If   Me .IsRoot  Then
                    
Return   Nothing
                
End   If
                
Return  gParent
            
End   Get
        
End Property

        
' '' <summary>
         ' '' 树的深度
         ' '' </summary>
         Public   ReadOnly   Property  Level()  As   Integer
            
Get
                
If   Me .IsRoot  Then
                    
Return   0
                
End   If
                
Return   Me .Parent.Level  +   1
            
End   Get
        
End Property


        
' '' <summary>
         ' '' 当前节点是否是根节点
         ' '' </summary>
         Public   ReadOnly   Property  IsRoot()  As   Boolean
            
Get
                
Return  gIsRoot
            
End   Get
        
End Property

        
Private  gUserData  As   Object

        
' '' <summary>
         ' '' 获取或设置包含树节点有关数据的对象
         ' '' </summary>
         Public   Property  Tag()  As   Object
            
Get
                
Return  gUserData
            
End   Get
            
Set ( ByVal  value  As   Object )
                gUserData 
=  value
            
End   Set
        
End Property

        
Private  gItem  As  T
        
Public   Property  Item()  As  T
            
Get
                
Return  gItem
            
End   Get
            
Set ( ByVal  value  As  T)
                gItem 
=  value
            
End   Set
        
End Property


        
Friend  gChildren  As  NodeCollection( Of  T)

        
' '' <summary>
         ' '' 获取第一个子树节点
         ' '' </summary>
         Public   ReadOnly   Property  FirstNode()  As  Node( Of  T)
            
Get
                
If  gChildren.Count  =   0   Then
                    
Return   Nothing
                
End   If
                
Return  gChildren( 0 )
            
End   Get
        
End Property

        
' '' <summary>
         ' '' 获取最后一个子树节点
         ' '' </summary>
         Public   ReadOnly   Property  LastNode()  As  Node( Of  T)
            
Get
                
If  gChildren.Count  =   0   Then
                    
Return   Nothing
                
End   If
                
Return  gChildren(gChildren.Count  -   1 )
            
End   Get
        
End Property


        
Private  gNodes  As  NodeCollection( Of  T)

        
' '' <summary>
         ' '' 当前节点的节点集合
         ' '' </summary>
         Public   ReadOnly   Property  Nodes()  As  NodeCollection( Of  T)
            
Get
                
Return  gNodes
            
End   Get
        
End Property

        
' '' <summary>
         ' '' 当前节点在节点集合中的位置
         ' '' </summary>
         Public   ReadOnly   Property  Index()  As   Integer
            
Get
                
Return  GetIndex()
            
End   Get
        
End Property

        
Private   Function  GetIndex()  As   Integer
            
If   Me .IsRoot  Then
                
Return   0
            
End   If

            
Return   Me .Parent.Nodes.IndexOf( Me )
        
End Function

        
' '' <summary>
         ' '' 获取下一个同级树节点
         ' '' </summary>
         Public   ReadOnly   Property  NextNode()  As  Node( Of  T)
            
Get
                
If   Me .IsRoot  OrElse   Me .Index  +   1   >   Me .Parent.Nodes.Count  Then
                    
Return   Nothing
                
End   If

                
Return   Me .Parent.Nodes.Item( Me .Index  +   1 )
            
End   Get
        
End Property

        
' '' <summary>
         ' '' 获取上一个同级树节点
         ' '' </summary>
         Public   ReadOnly   Property  PrevNode()  As  Node( Of  T)
            
Get
                
If   Me .IsRoot  OrElse   Me .Index  -   1   <   0   Then
                    
Return   Nothing
                
End   If

                
Return   Me .Parent.Nodes.Item( Me .Index  -   1 )
            
End   Get
        
End Property

        
Private   Sub  Initialzie()
            gNodes 
=   New  NodeCollection( Of  T)( Me )
            gChildren 
=   New  NodeCollection( Of  T)( Me )
            gByProperty 
=   Not  uSystem.uReflection.MemberInfoFunction.TypeHasFields( GetType (T))
        
End Sub

        
Sub   New ()
            Initialzie()
        
End Sub

        
Sub   New ( ByVal  item  As  T)
            gItem 
=  item

            Initialzie()
        
End Sub

        
Public   Function  GetNodeCount( ByVal  includeSubNodes  As   Boolean As   Integer
            
Dim  mCount  As   Integer   =  gChildren.Count
            
If  includeSubNodes  Then
                
Dim  mIndex  As   Integer   =   0
                
Do   While  mIndex  <  gChildren.Count
                    mCount 
+=  gChildren(mIndex).GetNodeCount( True )
                    mIndex 
+=   1
                
Loop
            
End   If

            
Return  mCount
        
End Function

        
Public   Sub  Remove()
            
If   Me .IsRoot  Then
                
Throw   New  Exception( " 不能移除根节点 " )
            
End   If
            
Me .Parent.Nodes.RemoveAt( Me .Index)
        
End Sub


        
Private  gTable  As  DataTable
        
Private  gByProperty  As   Boolean

        
' '' <summary>
         ' '' 将当前节点树转换为表
         ' '' </summary>
         ' '' <param name="includeSubNodes">是否包括子节点的T对象</param>
         Public   Function  ConvertToDataTable( ByVal  includeSubNodes  As   Boolean As  DataTable
            gTable 
=  uSystem.uReflection.DatasFunction.CreateTableFromType( GetType (T))

            
If  gTable.Columns.Count  =   0   Then
                
If  gByProperty  Then
                    
Throw   New  Exception( " 对象无属性列 " )
                
Else
                    
Throw   New  Exception( " 对象无字段列 " )
                
End   If
            
End   If

            
Me .ForEach( New  Action( Of  T)( AddressOf  GetDataTableDatasAction), includeSubNodes)

            gTable.AcceptChanges()

            
Return  gTable
        
End Function


        
Private   Sub  GetDataTableDatasAction( ByVal  item  As  T)
            uSystem.uReflection.DatasFunction.ItemAppendToTable(
Of  T)(item, gTable)
        
End Sub

        
' '' <summary>
         ' '' 将当前节点树转换为TreeNode
         ' '' </summary>
         ' '' <param name="memberNameForTreeNodeText">TreeNode的Text值对应的T对象属性名或字段名</param>
         ' '' <param name="includeSubNodes">是否包括子节点</param>
         ' '' <remarks>TreeNode的Tag存T对象值</remarks>
         Public   Function  ConvertToTreeNode( ByVal  memberNameForTreeNodeText  As   String ByVal  includeSubNodes  As   Boolean As  Windows.Forms.TreeNode
            CheckValid(gByProperty, memberNameForTreeNodeText)

            
Dim  mTreeNode  As  System.Windows.Forms.TreeNode  =  ConvertToTreeNode( Me , gByProperty, memberNameForTreeNodeText, memberNameForTreeNodeText)

            
If  includeSubNodes  Then  AppendTreeNode(mTreeNode,  Me , gByProperty, memberNameForTreeNodeText, memberNameForTreeNodeText)

            
Return  mTreeNode
        
End Function

        
' '' <summary>
         ' '' 将当前节点下的节点集合转换为TreeNode集合
         ' '' </summary>
         ' '' <param name="memberNameForTreeNodeText">TreeNode的Text值对应的T对象属性名或字段名</param>
         ' '' <param name="includeSubNodes">是否包括子节点</param>
         ' '' <remarks>TreeNode的Tag存T对象值</remarks>
         Public   Function  ConvertToTreeNodes( ByVal  memberNameForTreeNodeText  As   String ByVal  includeSubNodes  As   Boolean As  Windows.Forms.TreeNode()
            CheckValid(gByProperty, memberNameForTreeNodeText)
            
Dim  mResult( Me .Nodes.Count  -   1 As  TreeNode

            
Dim  mIndex  As   Integer   =   0
            
For   Each  node  As  Node( Of  T)  In   Me .Nodes
                mResult(mIndex) 
=  node.ConvertToTreeNode(memberNameForTreeNodeText, includeSubNodes)
                mIndex 
+=   1
            
Next

            
Return  mResult
        
End Function

        
Public   Function  ConvertToTreeNode( ByVal  memberNameForTreeNodeText  As   String ByVal  memberNameForTreeNodeName  As   String ByVal  includeSubNodes  As   Boolean As  Windows.Forms.TreeNode
            CheckValid(gByProperty, memberNameForTreeNodeText)

            
Dim  mTreeNode  As  System.Windows.Forms.TreeNode  =  ConvertToTreeNode( Me , gByProperty, memberNameForTreeNodeText, memberNameForTreeNodeName)

            
If  includeSubNodes  Then  AppendTreeNode(mTreeNode,  Me , gByProperty, memberNameForTreeNodeText, memberNameForTreeNodeName)

            
Return  mTreeNode
        
End Function

        
' '' <summary>
         ' '' 数据存于TreeNode的Tag中,要求T具有New()构造函数
         ' '' </summary>
         Public   Sub  ImportFromTreeNodeChild( ByVal  treeNode  As  TreeNode)
            
Me .Nodes.Clear()

            
Me .gItem  =   CType (System.Activator.CreateInstance( GetType (T)), T)

            
For   Each  item  As  TreeNode  In  treeNode.Nodes
                AppendNodeFromTreeNode(item, 
Me )
            
Next

        
End Sub

        
Private   Shared   Sub  AppendNodeFromTreeNode( ByVal  treeNode  As  TreeNode,  ByVal  Node  As  Node( Of  T))

            
Dim  mCurrentNode  As  Node( Of  T)  =   Nothing

            
Dim  tmp  As  T  =  uReflection.DatasFunction.Copy( Of  T)(treeNode.Tag)
            mCurrentNode 
=  Node.Nodes.Add(tmp)

            
For   Each  item  As  TreeNode  In  treeNode.Nodes
                AppendNodeFromTreeNode(item, mCurrentNode)
            
Next
        
End Sub

        
Private   Shared   Sub  AppendTreeNode( ByVal  treeNode  As  Windows.Forms.TreeNode,  ByVal  node  As  Node( Of  T),  ByVal  byProperty  As   Boolean ByVal  memberNameForTreeNodeText  As   String ByVal  memberNameForTreeNodeName  As   String )
            
For   Each  n  As  Node( Of  T)  In  node.gChildren

                
Dim  mCurrentTreeNode  As  Windows.Forms.TreeNode  =  ConvertToTreeNode(n, byProperty, memberNameForTreeNodeText, memberNameForTreeNodeName)

                treeNode.Nodes.Add(mCurrentTreeNode)

                AppendTreeNode(mCurrentTreeNode, n, byProperty, memberNameForTreeNodeText, memberNameForTreeNodeName)

            
Next

        
End Sub

        
Private   Shared   Function  ConvertToTreeNode( ByVal  node  As  Node( Of  T),  ByVal  byProperty  As   Boolean ByVal  memberNameForTreeNodeText  As   String ByVal  memberNameForTreeNodeName  As   String As  System.Windows.Forms.TreeNode
            
Dim  mTextValue  As   Object
            
Dim  mNameValue  As   Object

            
If  byProperty  Then
                mTextValue 
=  uReflection.MemberInfoFunction.GetPropertyResult(node.Item, memberNameForTreeNodeText,  Nothing )
                mNameValue 
=  uReflection.MemberInfoFunction.GetPropertyResult(node.Item, memberNameForTreeNodeName,  Nothing )
            
Else
                mTextValue 
=  uReflection.MemberInfoFunction.GetFieldResult(node.Item, memberNameForTreeNodeText)
                mNameValue 
=  uReflection.MemberInfoFunction.GetFieldResult(node.Item, memberNameForTreeNodeName)
            
End   If

            
If  mTextValue  Is   Nothing   Then
                mTextValue 
=   " Root "
            
End   If

            
If  mNameValue  Is   Nothing   Then
                mNameValue 
=   ""
            
End   If

            
Dim  mTreeNode  As   New  System.Windows.Forms.TreeNode(mTextValue.ToString)
            
With  mTreeNode
                .Name 
=   CStr (mNameValue)
                .Tag 
=  node.Item
            
End   With

            
Return  mTreeNode
        
End Function

        
Private   Sub  CheckValid( ByVal  byProperty  As   Boolean ByVal  nameOfTreeNodeText  As   String )
            
If  byProperty  Then
                
Dim  mPropertyInfo  As  System.Reflection.PropertyInfo  =   GetType (T).GetProperty(nameOfTreeNodeText)
                
If  mPropertyInfo  Is   Nothing   Then
                    
Throw   New  Exception( " 属性名无效 " )
                    
If   Not  mPropertyInfo.CanRead  Then
                        
Throw   New  Exception( " 属性名不可读 " )
                    
End   If
                
End   If
            
Else
                
Dim  mFieldInfo  As  System.Reflection.FieldInfo  =   GetType (T).GetField(nameOfTreeNodeText)
                
If  mFieldInfo  Is   Nothing   Then
                    
Throw   New  Exception( " 字段名无效 " )
                
End   If
            
End   If
        
End Sub


        
' '' <summary>
         ' '' 对每个节点执行指定操作
         ' '' </summary>
         ' '' <param name="action">对指定的对象执行操作的方法</param>
         ' '' <param name="includeSubNodes">是否包括子节点</param>
         Public   Sub  ForEach( ByVal  action  As  Action( Of  Node( Of  T)),  ByVal  includeSubNodes  As   Boolean )
            Node(
Of  T).ForEach( Me , action, includeSubNodes)
        
End Sub

        
Public   Shared   Sub  ForEach( ByVal  node  As  Node( Of  T),  ByVal  action  As  Action( Of  Node( Of  T)),  ByVal  includeSubNodes  As   Boolean )
            
For   Each  n  As  Node( Of  T)  In  node.gChildren
                action.Invoke(n)

                
If  includeSubNodes  Then  ForEach(n, action,  True )
            
Next
        
End Sub

        
' '' <summary>
         ' '' 对每个T对象执行指定操作
         ' '' </summary>
         ' '' <param name="action">对指定的对象执行操作的方法</param>
         ' '' <param name="includeSubNodes">是否包括子节点的T对象</param>
         Public   Sub  ForEach( ByVal  action  As  Action( Of  T),  ByVal  includeSubNodes  As   Boolean )
            Node(
Of  T).ForEach( Me , action, includeSubNodes)
        
End Sub

        
Public   Shared   Sub  ForEach( ByVal  node  As  Node( Of  T),  ByVal  action  As  Action( Of  T),  ByVal  includeSubNodes  As   Boolean )
            
For   Each  n  As  Node( Of  T)  In  node.gChildren
                action.Invoke(n.Item)


                
If  includeSubNodes  Then  ForEach(n, action,  True )
            
Next
        
End Sub

        
Public   Function  FindFirstNode( ByVal  memberName  As   String ByVal  value  As   Object As  Node( Of  T)
            
Dim  mType  As  Type  =   GetType (T)

            
If   Not  uSystem.uReflection.MemberInfoFunction.TypeHasMember(mType, memberName)  Then
                
Throw   New  Exception( String .Format( " 无此成员名 :{0} " , memberName))
            
End   If

            
If  gByProperty  Then
                
If   Not  mType.GetProperty(memberName).CanRead  Then
                    
Throw   New  Exception( String .Format( " 成员名不可读 :{0} " , memberName))
                
End   If
            
End   If

            
Dim  mResult  As  Node( Of  T)  =   Nothing
            FindFirstNode(mType, memberName, value, 
Me , mResult)

            
Return  mResult
        
End Function

        
Private   Sub  FindFirstNode( ByVal  t  As  Type,  ByVal  memberName  As   String ByVal  Value  As   Object ByVal  node  As  Node( Of  T),  ByRef  result  As  Node( Of  T))

            
For   Each  n  As  Node( Of  T)  In  node.gChildren
                
If  gByProperty  Then
                    
If  t.GetProperty(memberName).GetValue(n.Item,  Nothing ).Equals(Value)  Then
                        result 
=  n
                        
Exit Sub
                    
End   If
                
Else
                    
If  t.GetField(memberName).GetValue(n.Item).Equals(Value)  Then
                        result 
=  n
                        
Exit Sub
                    
End   If
                
End   If

                FindFirstNode(t, memberName, Value, n, result)
            
Next
        
End Sub


        
Public   Function  Clone()  As  Node( Of  T)
            
Return  uSystem.uRuntime.uSerialization.SerializeHelper.Clone( Of  Node( Of  T))( Me )
        
End Function


    
End Class

End Namespace

 

Namespace  LzmTW.uSystem.uCollection
    
' '' <summary>
     ' '' 树节点集合
     ' '' </summary>
     ' '' <remarks>LzmTW 20061111</remarks>
     < Serializable() >  _
    
Public   Class  NodeCollection( Of  T)
        
Inherits  System.Collections.ObjectModel.Collection( Of  Node( Of  T))

        
Private  gOwner  As  Node( Of  T)

        
Friend   Sub   New ( ByVal  node  As  Node( Of  T))
            gOwner 
=  node
        
End Sub

        
Public   Shadows   Function  Add( ByVal  Value  As  T)  As  Node( Of  T)
            
Dim  mNode  As   New  Node( Of  T)(Value)

            Add(mNode)
            gOwner.gChildren.Add(mNode)

            
Return  mNode
        
End Function

        
Private   Shadows   Sub  Add( ByVal  item  As  Node( Of  T))
            
With  item
                .gParent 
=  gOwner
                .gIsRoot 
=   False
            
End   With

            
MyBase .Add(item)
        
End Sub

        
Public   Shadows   Sub  RemoveAt( ByVal  index  As   Integer )
            
If   Not  IsValidIndex(index)  Then
                
Throw   New  Exception( " 索引无效 " )
            
End   If

            
Dim  mNode  As  Node( Of  T)  =   Me .Item(index)
            Remove(mNode)

            gOwner.gChildren.Remove(mNode)
        
End Sub

        
Public   Shadows   Sub  Remove( ByVal  index  As   Integer )
            
Me .RemoveAt(index)
        
End Sub

        
Private   Shadows   Function  Remove( ByVal  item  As  Node( Of  T))  As   Boolean
            
Return   MyBase .Remove(item)
        
End Function

        
Public   Shadows   Sub  Insert( ByVal  index  As   Integer ByVal  Value  As  T)
            
If   Not  IsValidIndex(index)  Then
                
Throw   New  Exception( " 索引无效 " )
            
End   If

            
Dim  mNode  As   New  Node( Of  T)(Value)

            Insert(index, mNode)
            gOwner.gChildren.Insert(index, mNode)
        
End Sub

        
Private   Shadows   Sub  Insert( ByVal  index  As   Integer ByVal  item  As  Node( Of  T))
            
With  item
                .gParent 
=  gOwner
                .gIsRoot 
=   False
            
End   With

            
MyBase .Insert(index, item)
        
End Sub

        
Public   Overloads   Sub  Clear()
            
MyBase .Clear()
            
If  gOwner.gChildren.Count  >   0   Then  gOwner.gChildren.Clear()
        
End Sub

        
Private   Function  IsValidIndex( ByVal  index  As   Integer As   Boolean
            
If  index  >=   0   Then
                
Return  index  <   Me .Count
            
End   If

            
Return   False
        
End Function

    
End Class
End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink

    
' '' <summary>
     ' '' 自联表数据集合。如果加载的数据是Code,Name形式,须调用New(codeFormat)构造函数以指定codeFormat形式.
     ' '' </summary>
     ' '' <typeparam name="T_ID_DataType">自联表键类型,或是Integer或是String</typeparam>
     ' '' <typeparam name="T">自联表数据类</typeparam>
     ' '' <remarks>LzmTW 20061111</remarks>
     < Serializable() >  _
    
Public   Class  SinceLinkItemCollection( Of  T_ID_DataType, T  As  SinceLinkItemBase( Of  T_ID_DataType))
        
Inherits  System.Collections.ObjectModel.Collection( Of  T)

        
< NonSerialized() >  _
        
Private  gNode  As  Node( Of  T)

        
Private  gCodeFormat  As   String
        
Private  gFileName  As   String   =  AppDomain.CurrentDomain.BaseDirectory  &   " {0}.{1}s.dat "

        
Sub   New ()
            gFileName 
=   String .Format(gFileName, System.Reflection.Assembly.GetEntryAssembly.ManifestModule.Name,  GetType (T).Name)
        
End Sub

        
' '' <param name="codeFormat">形如“00,000,0000”</param>
         Sub   New ( ByVal  codeFormat  As   String )
            gCodeFormat 
=  codeFormat
            gFileName 
=   String .Format(gFileName, System.Reflection.Assembly.GetEntryAssembly.ManifestModule.Name,  GetType (T).Name)
        
End Sub

        
Public   ReadOnly   Property  Node()  As  Node( Of  T)
            
Get
                
If  gNode  Is   Nothing   Then
                    
Me .RefleshNode()
                
End   If
                
Return  gNode
            
End   Get
        
End Property

        
Public   Shadows   Function  Add( ByVal  code  As   String ByVal  name  As   String As  T
            
Dim  mItem  As  T  =   CType (System.Activator.CreateInstance( GetType (T),  New   Object () {code, name}), T)
            
Me .Add(mItem)

            
Return  mItem
        
End Function

        
Public   Shadows   Sub  Add( ByVal  items  As  T())
            
For   Each  item  As  T  In  items
                Add(item)
            
Next
        
End Sub

        
Public   Shadows   Function  Add( ByVal  item  As  T)  As  T
            item.UpdateInformations(gCodeFormat)

            
MyBase .Add(item)

            
Return  item
        
End Function

        
' '' <summary>
         ' '' 转为自联表
         ' '' </summary>
         Public   Function  ExportSinceLinkDataSet()  As  DataSet

            
Dim  mDataSet  As   New  DataSet( " SinceLink " )
            
Dim  mTable  As  DataTable  =  CreateSinceLinkTable()
            mTable.TableName 
=   GetType (T).Name

            mDataSet.Tables.Add(mTable)

            
If   Me .Node  Is   Nothing   Then   Return  mDataSet

            
Dim  mCurrentID  As   Integer   =   0
            
Dim  mParentID  As   Integer   =   0

            
Dim  mNode  As  Node( Of  T)  =   Me .Node

            mNode.Tag 
=   0

            
' 首行
             Dim  mFirstRow  As  DataRow  =  CreateSinceLinkRow(mTable, mNode.Item)
            mFirstRow(
" ID " =   0
            mFirstRow(
" ParentID " =   - 1

            mTable.Rows.Add(mFirstRow)

            UpdateSinceLinkRow(mTable, 
Me .Node, mCurrentID)

            mTable.AcceptChanges()

            
Return  mDataSet
        
End Function

        
Private   Sub  UpdateSinceLinkRow( ByVal  table  As  DataTable,  ByVal  node  As  Node( Of  T),  ByRef  currentID  As   Integer )

            
For   Each  n  As  Node( Of  T)  In  node.gChildren
                
Dim  mRow  As  DataRow  =  CreateSinceLinkRow(table, n.Item)
                currentID 
+=   1

                mRow(
" ID " =  currentID
                mRow(
" ParentID " =  node.Tag

                table.Rows.Add(mRow)

                n.Tag 
=  currentID
                UpdateSinceLinkRow(table, n, currentID)
            
Next
        
End Sub

        
Private   Function  CreateSinceLinkRow( ByVal  table  As  DataTable,  ByVal  item  As  T)  As  DataRow
            
Dim  mRow  As  DataRow
            mRow 
=  uSystem.uReflection.DatasFunction.ItemToDataRow( Of  T)(item, table)
            
Return  mRow
        
End Function

        
Private   Function  CreateSinceLinkTable()  As  DataTable
            
Dim  tmpTable  As  DataTable  =  uSystem.uReflection.DatasFunction.CreateTableFromType( GetType (T))

            
With  tmpTable
                .TableName 
=   GetType (T).Name

                
If  .Columns.Contains( " ID " OrElse  .Columns.Contains( " ParentID " Then
                    
Throw   New  Exception( " 类已定义了ID或ParentID,无法生成自联表 " )
                
End   If

                
' 定义为整型
                .Columns.Add( " ParentID " GetType ( Integer ))
                .Columns.Add(
" ID " GetType ( Integer ))
            
End   With

            
Return  tmpTable
        
End Function

        
' '' <summary>
         ' '' 从自联表加载数据,表必须有ID,ParentID,Name字段,并且,有一项数据Name字段的值为“Root”以申明为根。
         ' '' </summary>
         Public   Sub  AppendItemsFromSinceLinkTable( ByVal  sinceLinkTable  As  DataTable)
            
Dim  mSinceLinkTable  As   New  SinceLinkTable( Of  T_ID_DataType, T)
            
With  mSinceLinkTable
                .Input(sinceLinkTable)

                gCodeFormat 
=  .CodeFormat
                Add(.Items)
            
End   With

        
End Sub

        
' '' <summary>
         ' '' 从树中加载数据
         ' '' </summary>
         Public   Sub  AppendItemsFromTree( ByVal  node  As  Node( Of  T))
            
Dim  mSinceLinkBlankNode  As   New  SinceLinkBlankCodeNode( Of  T_ID_DataType, T)
            
With  mSinceLinkBlankNode
                .SetNode(node)

                gCodeFormat 
=  .CodeFormat
                Add(.Items)
            
End   With
        
End Sub

        
Public   Sub  RefleshNode()
            gNode 
=  GetNode()
        
End Sub

        
Private   Function  GetNode()  As  Node( Of  T)
            
If   Me .Count  =   0   Then   Return   Nothing

            
Dim  mItem  As  T  =   CType (System.Activator.CreateInstance( GetType (T)), T)
            
With  mItem
                .gCode 
=   New   String ( " 0 " c, gCodeFormat.Replace( " , " c,  "" ).Length)
                .Name 
=   " Root "
            
End   With

            mItem.UpdateInformations(gCodeFormat)

            
Dim  mNode  As   New  Node( Of  T)(mItem)

            
Dim  mCurrentNode  As  Node( Of  T)
            
' 加首级
             For   Each  item  As  T  In   Me .Items

                
If  item.GetLevel  =   1   Then
                    mCurrentNode 
=  mNode.Nodes.Add(item)

                    
' 加子级
                    AppendItem(mCurrentNode)
                
End   If

            
Next

            
Return  mNode
        
End Function

        
Private   Sub  AppendItem( ByRef  node  As  Node( Of  T))
            
Dim  mCurrentNode  As  Node( Of  T)
            
For   Each  item  As  T  In  GetChildItem(node.Item)
                mCurrentNode 
=  node.Nodes.Add(item)

                AppendItem(mCurrentNode)
            
Next

        
End Sub

        
Public   Function  GetChildItem( ByVal  item  As  T)  As  System.Collections.ObjectModel.Collection( Of  T)
            
Dim  mList  As   New  System.Collections.ObjectModel.Collection( Of  T)

            
If  item.GetLevel  =  item.GetLevels  Then   Return  mList
            
For   Each  value  As  T  In   Me .Items
                
If  item.Code.StartsWith(value.GetParentKey)  AndAlso  value.GetParentID.Equals(item.GetID)  AndAlso  item.GetLevel  =  value.GetLevel  -   1   Then
                    mList.Add(value)
                
End   If
            
Next

            
Return  mList
        
End Function

        
Public   Function  Find( ByVal  memberName  As   String ByVal  Value  As   Object As  T

            
Dim  mType  As  Type  =   GetType (T)
            
Dim  mPropertyInfo  As  Reflection.PropertyInfo  =  mType.GetProperty(memberName)

            
If  mPropertyInfo  Is   Nothing   Then
                
Throw   New  Exception( String .Format( " 无此成员名 :{0} " , memberName))
            
Else
                
If   Not  mPropertyInfo.CanRead  Then
                    
Throw   New  Exception( String .Format( " 成员名不可读 :{0} " , memberName))
                
End   If
            
End   If

            
Dim  mResult  As  T  =   Nothing

            
For   Each  item  As  T  In   Me .Items
                
If  mPropertyInfo.GetValue(item,  Nothing ).Equals(Value)  Then
                    mResult 
=  item
                    
Exit   For
                
End   If
            
Next

            
Return  mResult
        
End Function

        
Public   Sub  CopyFrom( ByVal  collection  As  SinceLinkItemCollection( Of  T_ID_DataType, T))
            
With  collection
                
Me .Clear()
                
Me .gCodeFormat  =  .gCodeFormat
                
Me .gFileName  =  .gFileName
                
For   Each  item  As  T  In  .Items
                    
Me .Add( CType (item.Clone, T))
                
Next
            
End   With
        
End Sub

#Region  "文件数据的存储和读取"


        
Public   Sub  Read( ByVal  file  As   String )
            gFileName 
=  file
            Read()
        
End Sub

        
Public   Sub  Save( ByVal  file  As   String )
            gFileName 
=  file
            Save()
        
End Sub

        
Public   Sub  Read()
            ReadInternal()
        
End Sub

        
Public   Sub  Save()
            SaveInternal()
        
End Sub

        
Private   Sub  SaveInternal()
            uSystem.uRuntime.uSerialization.SerializeHelper.Save(
Of  SinceLinkItemCollection( Of  T_ID_DataType, T))(gFileName, uRuntime.uSerialization.FormatType.Binary,  Me )
        
End Sub

        
Private   Sub  ReadInternal()
            
Dim  tmp  As  SinceLinkItemCollection( Of  T_ID_DataType, T)
            tmp 
=  uSystem.uRuntime.uSerialization.SerializeHelper.Load( Of  SinceLinkItemCollection( Of  T_ID_DataType, T))(gFileName, uRuntime.uSerialization.FormatType.Binary)
            
Me .CopyFrom(tmp)
            tmp.Clear()
            tmp 
=   Nothing
        
End Sub
#End Region

    
End Class

End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink
    
' '' <summary>
     ' '' 自联表数据类的派生类
     ' '' </summary>
     ' '' <typeparam name="T_ID_DataType">自联表键类型,或是Integer或是String</typeparam>
     ' '' <remarks>LzmTW 20061111</remarks>
     < Serializable() >  _
    
Public   MustInherit   Class  SinceLinkItemBase( Of  T_ID_DataType)

        
Private  gName  As   String
        
Friend  gCode  As   String

        
< NonSerialized() >  _
        
Private  gCodeInformation  As  SinceLinkCodeInformation

        
Sub   New ()
        
End Sub

        
Sub   New ( ByVal  code  As   String ByVal  name  As   String )
            gName 
=  name
            gCode 
=  code
        
End Sub

        
Public   ReadOnly   Property  Code()  As   String
            
Get
                
Return  gCode
            
End   Get
        
End Property

        
Public   Property  Name()  As   String
            
Get
                
Return  gName
            
End   Get
            
Set ( ByVal  value  As   String )
                gName 
=  value
            
End   Set
        
End Property

        
Friend   Sub  UpdateInformations( ByVal  codeFormat  As   String )
            gCodeInformation 
=   New  SinceLinkCodeInformation(codeFormat)
            gCodeInformation.SetCode(gCode)
        
End Sub

        
Friend   Function  GetLevel()  As   Integer
            
Return  gCodeInformation.Level
        
End Function

        
Friend   Function  GetID()  As  T_ID_DataType
            
Return   CType (System.Convert.ChangeType(gCodeInformation.ID,  GetType (T_ID_DataType)), T_ID_DataType)
        
End Function

        
Friend   Function  GetParentID()  As  T_ID_DataType
            
Return   CType (System.Convert.ChangeType(gCodeInformation.ParentID,  GetType (T_ID_DataType)), T_ID_DataType)
        
End Function

        
Friend   Function  GetParentKey()  As   String
            
Return  gCodeInformation.ParentKey
        
End Function

        
Friend   Function  GetLevels()  As   Integer
            
Return  gCodeInformation.Levels
        
End Function

        
Public   Function  Clone()  As  SinceLinkItemBase( Of  T_ID_DataType)
            
Return  uSystem.uRuntime.uSerialization.SerializeHelper.Clone( Of  SinceLinkItemBase( Of  T_ID_DataType))( Me )
        
End Function

    
End Class

End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink

    
' '' <summary>
     ' '' 处理数据本身是自联表
     ' '' </summary>
     ' '' <typeparam name="T_ID_DataType">自联表键类型,或是Integer或是String</typeparam>
     ' '' <typeparam name="T">自联表数据类</typeparam>
     ' '' <remarks>LzmTW 20061111</remarks>
     Friend   Class  SinceLinkTable( Of  T_ID_DataType, T  As  SinceLinkItemBase( Of  T_ID_DataType))
        
Private  gDataTable  As  DataTable

        
Private  gFilterFormat  As   String
        
Private  gNode  As  Node( Of  T)

        
Private  gBlankNode  As   New  SinceLinkBlankCodeNode( Of  T_ID_DataType, T)

        
Public   ReadOnly   Property  Items()  As  T()
            
Get
                
Return  gBlankNode.Items
            
End   Get
        
End Property

        
Public   ReadOnly   Property  CodeFormat()  As   String
            
Get
                
Return  gBlankNode.CodeFormat
            
End   Get
        
End Property

        
Sub   New ()
            
If   GetType (T).GetMethod( " GetID " , Reflection.BindingFlags.NonPublic  Or  Reflection.BindingFlags.Instance).ReturnType  Is   GetType ( String Then
                gFilterFormat 
=   " ParentID = '{0}' "
            
Else
                gFilterFormat 
=   " ParentID = {0} "
            
End   If
        
End Sub

        
Public   Sub   Input ( ByVal  table  As  DataTable)
            
If   Not   Me .IsSinceLinkTable(table)  Then   Throw   New  Exception( " 表不是自联表.若是,需有ID、ParentID字段和Name字段. " )
            
If  table.Rows.Count  =   0   Then   Throw   New  Exception( " 无数据 " )

            
Me .Copy(table)

            
Me .CreateNode()

            gBlankNode.SetNode(gNode)

            
Me .Clear()

        
End Sub

        
Private   Function  IsSinceLinkTable( ByVal  table  As  DataTable)  As   Boolean
            
With  table.Columns
                
If  .Contains( " ID " Then
                    
If  .Contains( " ParentID " Then
                        
Return  .Contains( " Name " )
                    
End   If
                
End   If
            
End   With

            
Return   False
        
End Function

        
Private   Sub  Copy( ByVal  table  As  DataTable)
            gDataTable 
=  table.Clone
            gDataTable.Load(table.CreateDataReader)
            gDataTable.AcceptChanges()
        
End Sub

        
Private   Sub  CreateNode()

            
Dim  mRows()  As  DataRow  =  gDataTable.Select( " Name = 'Root' " )
            
If  mRows.Length  =   0   Then
                
Throw   New  Exception( " 首位ID数据行的Name字段须有Root值示为根 " )
            
Else
                
If  mRows.Length  >   1   Then
                    
Throw   New  Exception( " 只能有一项数据行的Name字段为Root值 " )
                
End   If
            
End   If

            
Dim  mItem  As  T  =   CType (System.Activator.CreateInstance( GetType (T)), T)
            mItem.Name 
=   " Root "

            gNode 
=   New  Node( Of  T)(mItem)

            AppendNode(mRows(
0 ).Item( " ID " ), gNode)

        
End Sub

        
Private   Sub  AppendNode( ByVal  ParentID  As   Object ByVal  node  As  Node( Of  T))
            
Dim  mDataView  As  DataView  =  GetDataView(ParentID)

            
Dim  mCount  As   Integer   =  mDataView.Count
            
If  mCount  =   0   Then   Exit Sub

            
Dim  mNode  As  Node( Of  T)  =   Nothing

            
For   Each  rowView  As  DataRowView  In  mDataView
                mNode 
=  node.Nodes.Add(CreateItem(rowView))

                AppendNode(rowView.Item(
" ID " ), mNode)
            
Next

        
End Sub

        
Private   Function  GetDataView( ByVal  ParentID  As   Object As  DataView
            
Return   New  DataView(gDataTable,  String .Format(gFilterFormat, ParentID),  " ID " , DataViewRowState.CurrentRows)
        
End Function

        
Private   Function  CreateItem( ByVal  rowView  As  DataRowView)  As  T
            
Dim  mItem  As  T
            mItem 
=   CType (System.Activator.CreateInstance( GetType (T)), T)

            
For   Each  p  As  Reflection.PropertyInfo  In   GetType (T).GetProperties
                
If  p.CanWrite  Then
                    
If  rowView.DataView.Table.Columns.Contains(p.Name)  Then
                        
Dim  obj  As   Object   =  rowView.Item(p.Name)
                        
If  obj  Is  DBNull.Value  Then
                            obj 
=   Nothing
                        
End   If

                        obj 
=  System.Convert.ChangeType(obj, Type.GetTypeCode(p.PropertyType))

                        p.SetValue(mItem, obj, 
Nothing )
                    
End   If
                
End   If
            
Next

            
Return  mItem
        
End Function

        
Private   Sub  Clear()
            gDataTable.Clear()
            gDataTable.Dispose()

            gNode.Nodes.Clear()

        
End Sub
    
End Class

End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink
    
' '' <summary>
     ' '' 析取Code的信息以生成树
     ' '' </summary>
     ' '' <remarks>LzmTW 20061111</remarks>
     Friend   Class  SinceLinkCodeInformation
        
Private  gCode  As   String
        
Private  gCodeFormat  As   String   =   " 00,00,00 "

        
' 当前层级
         Private  gLevel  As   Integer
        
' 层数
         Private  gLevels  As   Integer

        
Private  gID  As   String
        
Private  gParentID  As   String

        
' 代码的各组ID位数
         Private  gIDLengths()  As   Integer

        
Private  gParentKey  As   String

        
Sub   New ( ByVal  codeFormat  As   String )
            gCodeFormat 
=  codeFormat

            
Dim  mIDArray()  As   String   =  gCodeFormat.Split( " , " c)
            
ReDim  gIDLengths(mIDArray.Length  -   1 )
            
For  i  As   Integer   =   0   To  mIDArray.Length  -   1
                gIDLengths(i) 
=  mIDArray(i).Length
            
Next

            gLevels 
=  gIDLengths.Length
        
End Sub

        
Public   ReadOnly   Property  Level()  As   Integer
            
Get
                
Return  gLevel
            
End   Get
        
End Property

        
Public   ReadOnly   Property  Levels()  As   Integer
            
Get
                
Return  gLevels
            
End   Get
        
End Property

        
Public   ReadOnly   Property  ID()  As   String
            
Get
                
Return  gID
            
End   Get
        
End Property

        
Public   ReadOnly   Property  ParentID()  As   String
            
Get
                
Return  gParentID
            
End   Get
        
End Property

        
Public   ReadOnly   Property  ParentKey()  As   String
            
Get
                
Return  gParentKey
            
End   Get
        
End Property


        
Public   Sub  SetCode( ByVal  code  As   String )
            gCode 
=  code
            GetIDInfos()
        
End Sub

        
Private   Sub  GetIDInfos()
            
Dim  tmpIDInfos(gLevels  -   1 As   String

            
Dim  mCurrentIndex  As   Integer   =   0
            
For  i  As   Integer   =   0   To  gLevels  -   1
                tmpIDInfos(i) 
=  gCode.Substring(mCurrentIndex, gIDLengths(i))
                mCurrentIndex 
+=  gIDLengths(i)
            
Next

            
For  i  As   Integer   =  gLevels  -   1   To   0   Step   - 1
                
If   Not  System.Text.RegularExpressions.Regex.IsMatch(tmpIDInfos(i),  " ^0+$ " Then
                    gLevel 
=  i  +   1
                    gID 
=  tmpIDInfos(i)
                    
If  i  =   0   Then
                        gParentID 
=   New   String ( " 0 " c, gIDLengths( 0 ))
                        gParentKey 
=   New   String ( " 0 " c, gIDLengths( 0 ))
                    
Else
                        gParentID 
=  tmpIDInfos(i  -   1 )

                        
For  k  As   Integer   =   0   To  i  -   1
                            gParentKey 
+=  tmpIDInfos(k)
                        
Next
                    
End   If

                    
Exit   For
                
End   If
            
Next

        
End Sub
    
End Class
End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink

    
' '' <summary>
     ' '' 处理树情形的数据,转换为Code,Name形式
     ' '' </summary>
     ' '' <typeparam name="T_ID_DataType">自联表键类型,或是Integer或是String</typeparam>
     ' '' <typeparam name="T">自联表数据类</typeparam>
     ' '' <remarks>LzmTW 20061111</remarks>
     Friend   Class  SinceLinkBlankCodeNode( Of  T_ID_DataType, T  As  SinceLinkItemBase( Of  T_ID_DataType))
        
Private  gList  As   New  ArrayList
        
Private  gItems  As  T()

        
Private  gCodeFormat  As   String
        
Private  gNode  As  Node( Of  T)

        
Private  gLevelLengths( 0 As   Integer

        
Public   ReadOnly   Property  Items()  As  T()
            
Get
                
Return  gItems
            
End   Get
        
End Property

        
Public   ReadOnly   Property  CodeFormat()  As   String
            
Get
                
Return  gCodeFormat
            
End   Get
        
End Property

        
Public   Sub  SetNode( ByVal  node  As  Node( Of  T))
            gNode 
=  node

            GetlevelLengths()

            UpdateCode()

            Clear()
        
End Sub

        
Private   Sub  GetlevelLengths()
            
Dim  mLevels  As   Integer   =   0

            GetLevelLengths(
0 , gNode, gLevelLengths, mLevels)

            
Dim  tmpFormat(mLevels  -   1 As   String
            
For  i  As   Integer   =   0   To  mLevels  -   1
                gLevelLengths(i) 
=  gLevelLengths(i).ToString.Length
                tmpFormat(i) 
=   New   String ( " 0 " c, gLevelLengths(i))
            
Next

            gCodeFormat 
=   String .Join( " , " , tmpFormat)
        
End Sub

        
Private   Sub  GetLevelLengths( ByVal  ParentID  As   Object ByVal  node  As  Node( Of  T),  ByRef  levelengths()  As   Integer ByRef  levels  As   Integer )

            
Dim  mCount  As   Integer   =  node.Nodes.Count
            
If  mCount  =   0   Then   Exit Sub

            
Dim  mNode  As  Node( Of  T)  =   Nothing

            
For   Each  mNode  In  node.gChildren
                GetLevelLengths(node.Index, mNode, levelengths, levels)
            
Next

            
If  mNode.Level  >  node.Level  Then
                
If  mNode.Level  >  levels  Then
                    levels 
=  mNode.Level
                    
ReDim   Preserve  levelengths(levels  -   1 )
                    levelengths(mNode.Level 
-   1 =  mCount
                
Else
                    levelengths(mNode.Level 
-   1 =  Math.Max(mCount, levelengths(mNode.Level  -   1 ))
                
End   If
            
Else
                levelengths(mNode.Level 
-   1 =  Math.Max(mCount, levelengths(mNode.Level  -   1 ))
            
End   If

        
End Sub

        
Private   Sub  UpdateCode()
            gNode.Item.gCode 
=   ""
            UpdateCode(gNode)
            gNode.Item.gCode 
=   New   String ( " 0 " c, RightLength( 0 ))

            
ReDim  gItems(gList.Count  -   1 )
            gList.CopyTo(gItems)
        
End Sub

        
Private   Sub  UpdateCode( ByVal  node  As  Node( Of  T))
            
For   Each  n  As  Node( Of  T)  In  node.Nodes
                n.Item.gCode 
=  GetCode(n.Parent.Item.Code, n.Level, n.Index)
                gList.Add(n.Item)

                UpdateCode(n)

            
Next
        
End Sub

        
Private   Function  GetCode( ByVal  parentCode  As   String ByVal  level  As   Integer ByVal  index  As   Integer As   String

            
Return   String .Concat(GetParentKey(parentCode, level), GetCurrentID(index, level))
        
End Function

        
Private   Function  GetParentKey( ByVal  parentCode  As   String ByVal  level  As   Integer As   String
            
Return  parentCode.Substring( 0 , LeftLength(level  -   1 ))
        
End Function

        
Private   Function  GetCurrentID( ByVal  index  As   Integer ByVal  level  As   Integer As   String
            
Return  (index  +   1 ).ToString.PadLeft(gLevelLengths(level  -   1 ),  " 0 " c).PadRight(RightLength(level  -   1 ),  " 0 " c)
        
End Function

        
Private   Function  LeftLength( ByVal  level  As   Integer As   Integer
            
Dim  tmp  As   Integer   =   0
            
For  i  As   Integer   =   0   To  level  -   1
                tmp 
+=  gLevelLengths(i)
            
Next
            
Return  tmp
        
End Function

        
Private   Function  RightLength( ByVal  level  As   Integer As   Integer
            
Dim  tmp  As   Integer   =   0
            
For  i  As   Integer   =  level  To  gLevelLengths.Length  -   1
                tmp 
+=  gLevelLengths(i)
            
Next
            
Return  tmp
        
End Function

        
Private   Sub  Clear()
            
'  gNode.Nodes.Clear()

            gList.Clear()

            gLevelLengths 
=   Nothing
        
End Sub

    
End Class

End Namespace
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值