展示树与devPress

这两天正在建树。


目标有几个:

1. 信息在数据库中,程序自动装载。

2. 表要少,特别是数据信息只在一个表中为好。因为目前的程序分三种:

1) 演示程序,信息在xml 文件中为好。随时都能展示给其它人看。

2)小客户端程序,不需要连远端数据库,用本地的access数据库就可以工作。

3)客户端工作在连接远端数据库的情况下。


也就是说,基础信息,有可能从远端同步到本地。

所以,表要少。


而且,树的层级关系,目前来看,不同的被管对象是不对的,是动态变化的,我们不能说哪一层,具有什么特定的含义,所以,要建一个子从属于父的关联树。


然后,展示到界面上。


小团队开发,或是一个人开发,象我这样,最好先考虑界面。因为界面是工作量最大的,内存结构做得好,可不一定界面上就好显示。


一开始调研了一个小程序: HierarchyTree

http://www.codeproject.com/script/articles/download.aspx?file=/KB/aspnet/HierarchyTree/HierarchyTree.zip&rp=http://www.codeproject.com/Articles/140827/Dynamic-Binding-Of-Hierarchy-Data-Structure-To-Tre


这个例子,展示了一种通常的作法。

但从各个方面,我不喜欢。看来在C#里面处理树不是很方便。当然,也是作者没有写好。


      foreach (HierarchyTrees.HTree hTree in hierarchyTrees)     
        {
            HierarchyTrees.HTree parentNode = hierarchyTrees.Find(delegate(HierarchyTrees.HTree emp) { return emp.NodeID == hTree.UnderParent; });
            if (parentNode != null)
            {         
                foreach (TreeNode tn in tvHierarchyView.Nodes)
                {
                    if (tn.Value == parentNode.NodeID.ToString())
                    {
                        tn.ChildNodes.Add(new TreeNode(hTree.NodeDescription.ToString(), hTree.NodeID.ToString()));
                        
                    }
                    if (tn.ChildNodes.Count > 0)
                    {
                        foreach (TreeNode ctn in tn.ChildNodes)
                        {
                            //RecursiveChild(ctn, parentNode.NodeID.ToString(), hTree);
                        }
                    }
                }                
            }
            else
            {               
                tvHierarchyView.Nodes.Add(new TreeNode(hTree.NodeDescription, hTree.NodeID.ToString()));
            } 
            }     
        tvHierarchyView.ExpandAll(); 
    }


这里我们看到,作者进行了两次迭代。比较糟的做法。

通常来讲,应当几步:

1) 在内存中建树。

2) 插入到界面。

插入界面的过程,有两个功能,需要注意:一个是在内存树中,如何遍历,如何快速定位。

一个是在界面树中,如何快速定位。

所以,在建内存数,和插入界面的时候,应当伴随建一个hash 表,或是快速map 之类的,两棵树都要有。

否则,代码就这成这位兄台这样:看起来很短,但究其实质,很糟。


为什么两步呢?以前我很喜欢一步到位,这样好处是,不用自己建树了,直接用界面控件的树就好了。不能说不好,因为这样有一个很重要的好处:不需要进行内存与界面的同步工作。对于动态树,这的确是要小心处理的,如果内存树还有界面树又分别建了索引,同步的工作量,还是有的。


但,编程,一味图快,图简单,问题也多。因为程序和人一样,是要腐烂的。总有一天,作者本人也不想闻一闻,究其原因,就是语义不清。

有了良好的内存结构,意味着复用性好:一方面,本程序内,其它模块好利用,另一方面这些代码,也便于复用到其它的项目中。


=============

本着这样的意图。我再次开始了脑子。


一般而言,大公司做的东西相对好一些。所以,我找到devExpress中的例子,花了大半天时间,建环境。

因为要跟代码。

看的例子是这个:用的是DX2011.2.5_src

XtraTreeList

刚接个电话,闲话少说吧,

这个例子,是从一个xml中读取信息,放到界面上。

可以猜测,一定有两个固有的字段:

ID

ParentID

这里,我再强调一下关键是你要有原码。看原码比一切理论都有实际意义。

另外,一定要建好调试环境。因为我手头的devExpress原码,也搞不清楚是从哪拿的,没有注释,可能这也是devexpress公司的策略,他们不会发布有注释的原码。

但也足够了。

展示树与devPress_第1张图片

至于,如何建这种环境,以后我来讲解。接了两个电话,已超时了。


<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true">
      <xs:complexType>
        <xs:choice maxOccurs="unbounded">
          <xs:element name="Table">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Id" type="xs:double" minOccurs="0" />
                <xs:element name="ParentId" type="xs:double" minOccurs="0" />
		<xs:element name="FirstName" type="xs:string" minOccurs="0" />
		<xs:element name="LastName" type="xs:string" minOccurs="0" />
		<xs:element name="JobTitle" type="xs:string" minOccurs="0" />
		<xs:element name="Phone" type="xs:string" minOccurs="0" />
		<xs:element name="EmailAddress" type="xs:string" minOccurs="0" />
		<xs:element name="AddressLine1" type="xs:string" minOccurs="0" />
		<xs:element name="City" type="xs:string" minOccurs="0" />
		<xs:element name="PostalCode" type="xs:string" minOccurs="0" />
		<xs:element name="CountryRegionName" type="xs:string" minOccurs="0" />
		<xs:element name="StateProvinceName" type="xs:string" minOccurs="0" />
		<xs:element name="GroupName" type="xs:string" minOccurs="0" />
		<xs:element name="BirthDate" type="xs:dateTime" minOccurs="0" />
		<xs:element name="HireDate" type="xs:dateTime" minOccurs="0" />
		<xs:element name="Gender" type="xs:string" minOccurs="0" />
		<xs:element name="MaritalStatus" type="xs:string" minOccurs="0" />
		<xs:element name="Title" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>  
  </xs:schema>
<Table>
    <Id>109</Id>
    <ParentId>0</ParentId>
    <FirstName>Bruce</FirstName>
    <LastName>Cambell</LastName>
    <JobTitle>Chief Executive Officer</JobTitle>
    <Phone>(417) 166-3268</Phone>
    <EmailAddress>[email protected]</EmailAddress>
    <AddressLine1>4228 S National Ave</AddressLine1>
    <City>Oaks</City>
    <PostalCode>65809</PostalCode>
    <StateProvinceName>California</StateProvinceName>
    <CountryRegionName>United States</CountryRegionName>
    <GroupName>Executive General and Administration</GroupName>
    <BirthDate>1957-09-06T00:00:00</BirthDate>
    <HireDate>2000-07-02T00:00:00</HireDate>
    <Gender>M</Gender>
    <MaritalStatus>M</MaritalStatus>
    <Title>Mr.</Title>
  </Table>
  <Table>
    <Id>42</Id>
    <ParentId>109</ParentId>
    <FirstName>Cindy</FirstName>
    <LastName>Haneline</LastName>
    <JobTitle>Information Services Manager</JobTitle>
    <Phone>(918) 161-3649</Phone>
    <EmailAddress>[email protected]</EmailAddress>
    <AddressLine1>2429 E. 15th Street</AddressLine1>
    <City>Vista</City>
    <PostalCode>74014</PostalCode>
    <StateProvinceName>California</StateProvinceName>
    <CountryRegionName>United States</CountryRegionName>
    <GroupName>Executive General and Administration</GroupName>
    <BirthDate>1973-12-23T00:00:00</BirthDate>
    <HireDate>1996-11-06T00:00:00</HireDate>
    <Gender>F</Gender>
    <MaritalStatus>S</MaritalStatus>
  </Table>



============

好了,开始。


DX2011.2.5_src\Sources\DevExpress.XtraTreeList\DevExpress.XtraTreeList\TreeList.cs(692):   


        protected const string defKeyFieldName = "ID",
            defParentFieldName = "ParentID",
            defImageIndexFieldName = "ImageIndex";
        public TreeList() : this(null) {
        }

这是最关键的几句话,我一开始跟了半天,才找到,原来是写死的。

初始化:

namespace DevExpress.XtraTreeList.Demos {
    public partial class NodesFiltering : DevExpress.XtraTreeList.Demos.TutorialControl {
        public NodesFiltering() {
            InitializeComponent();
            InitData();
            InitEditors();
            //InitFilter();
            treeList1.Columns["pkgName"].AllNodesSummary = true;
            treeList1.Columns["pkgName"].SummaryFooter = SummaryItemType.Count;
            treeList1.Columns["pkgName"].OptionsFilter.FilterPopupMode = FilterPopupMode.CheckedList;
            treeList1.OptionsView.ShowSummaryFooter = true;
        }



这里,我们改一下,不从xml,改从sqlserver中读。

        private void InitData() {
            string DBFileName = DevExpress.Utils.FilesHelper.FindingFileName(Application.StartupPath, "Data\\Employees.xml");
            if(DBFileName != "") {
                DataSet dataSet = new DataSet();
                //dataSet.ReadXml(DBFileName);




                using (SqlConnection connection = new SqlConnection(@"Data Source=127.0.0.1;Initial Catalog=AutoPack;Persist Security Info=True;User ID=sa;Password=12345"))
                {
                    connection.Open();//SSP_GET_HIERARCHY
                    using (SqlCommand command = new SqlCommand("select * from TBL_TREE_HIERARCHY", connection))
                    {
                        //command.CommandType = System.Data.CommandType.StoredProcedure;
                        //SqlDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.CloseConnection);


                        SqlDataAdapter da = new SqlDataAdapter(command);
                        //DataSet ds = new DataSet();
                        //fill the DataSet using default values for DataTable names, etc.

                        da.Fill(dataSet);
                    }
                }

                treeList1.DataSource = dataSet.Tables[0].DefaultView;
                treeList1.ForceInitialize();
                treeList1.ExpandAll();
                treeList1.BestFitColumns();
            }
        }


//这段代码,要是不处理,则确保表里有相关的字段:GroupName

        string currentGroupName;
        private void treeList1_GetStateImage(object sender, GetStateImageEventArgs e) {
            string[] groupNames = new string[] { "Administration", "Inventory", "Manufacturing", "Quality", "Research", "Sales" };
            currentGroupName =  (string)e.Node.GetValue("GroupName");
            e.NodeImageIndex = Array.FindIndex(groupNames, new Predicate<string>(IsCurrentGroupName));
        }
        private bool IsCurrentGroupName(string groupName) { return currentGroupName.Contains(groupName); }
 

数据库表如下:

USE [AutoPack]
GO

/****** Object:  Table [dbo].[TBL_TREE_HIERARCHY]    Script Date: 02/25/2014 17:45:37 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TBL_TREE_HIERARCHY](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ParentID] [int] NULL,
    [pkgName] [nvarchar](511) NULL,
    [NODE_DESCRIPTION] [nvarchar](511) NULL,
    [ImageIndex] [int] NULL,
    [UVERSION] [nvarchar](511) NULL,
    [VER] [nvarchar](511) NULL,
    [Title] [nvarchar](511) NULL,
    [GroupName] [nvarchar](511) NULL,
    [pkgFilename] [nvarchar](511) NULL
) ON [PRIMARY]

GO

内容,我随意写的
ID    ParentID    pkgName    NODE_DESCRIPTION    ImageIndex    UVERSION    VER    Title    GroupName    pkgFilename
1    0    a    Mathematics    0    A    1    wert    Administration    a.out
2    1    b    Algebra    NULL    A    2    fgg    Inventory    b.out
3    1    c    Geometry    0    A    3    s    Research    c.out
4    3    d    Triangle    0    A    1    ert    Research    d.out
5    4    e    By Relative Length    0    A    NULL    f    Research    e.out
6    4    f    By Internal Angle    0    A    232    s    Research    f.out
7    5    g    Equilateral Triangle    0    A    124    dfgwr    Research    g.out
8    5    h    Scalene Triangle    0    A    3    NULL    Quality    h.out
9    5    i    Isosceles Triangle    0    A    5    sfdg    Quality    i.out
10    6    j    Oblique > 90 Degree:Obtuse Angled Traingle    0    A    5    s    Quality    j.out
11    6    k    Oblique < 90 Degree:Acute Angled Traingle    0    A    5    f    Quality    k.out
12    6    l    Right Angled Triangle    0    A    4    sfg    Quality    l.out
13    2    m    Elementary Algebra    0    A    4    sf    Quality    m.out
14    2    n    Abstract Algebra    0    A    6    gsfgh    Manufacturing    n.out
15    2    o    Linear Algebra    0    A    345    fgj    Manufacturing    o.out
16    7    p    All Sides are Equal    0    A    3    fghj    Manufacturing    p.out


下一步,把这里改了在namespace DevExpress.XtraTreeList.Demos {
    partial class NodesFiltering {

...

            this.treeListColumn1.Caption = "包名称";
            this.treeListColumn1.FieldName = "pkgName";
            this.treeListColumn1.MinWidth = 33;
            this.treeListColumn1.Name = "treeListColumn1";
            this.treeListColumn1.Visible = true;
            this.treeListColumn1.VisibleIndex = 0;
            this.treeListColumn1.Width = 105;
            //
            // treeListColumn2
            //
            this.treeListColumn2.Caption = "文件名";
            this.treeListColumn2.FieldName = "pkgFilename";
            this.treeListColumn2.Name = "treeListColumn2";
            this.treeListColumn2.Visible = true;
            this.treeListColumn2.VisibleIndex = 1;
            this.treeListColumn2.Width = 106;


其它列删除

好了,跑起来,

展示树与devPress_第2张图片

你可能感兴趣的:(DevExpress)