C# uses XML and Treeview to implement complex data collection functions

  The data table of a project has not been finalized yet, but there are some certainties:
  1. It is relatively complex and may change;
  2. Most of the items are selected because the input items are similar;
  3. The application is a C/S form application.
  For such user needs, in order to quickly let users see the functional effects, XML can be used combined with Treeview to achieve it.
  The final input rendering:

   For the implementation of the above figure, the work that needs to be completed:

  1. Define XML file

<事故调查 value="" max="100">
	<气候因素 Value="" Formula="Item*1.5">
		<气温 type="Textbox" max="" min="" value="" />
		<湿度 type="Textbox" max="" min="" value="" />
	</气候因素>
	<地质灾害 Value="" Formula="Item" type="Radio">
		<option caption="泥石流" value="5" />
		<option caption="水灾" value="10" />
		<option caption="地震" value="20" />
	</地质灾害>
	<人为因素 Value="" Formula="Item" type="Checkbox">
		<input caption="管理失职" value="20" />
		<input caption="能力欠缺" value="20" />
		<input caption="制度不健全" value="15" />
	</人为因素>
</事故调查>

  2. Save the XML file into the data collection template and into the database. You can read it out when data entry is required.
  ⑴Add new template

string InsertQuery = $"INSERT INTO InputThemeXml(F01,F02,F03) VALUES (@ThemeName,@XmlData,@ThemeMemo)";
SqlCommand MyCommand = new SqlCommand(InsertQuery, DBConn);
MyCommand.Parameters.AddWithValue("@ThemeName", ThemeName);
MyCommand.Parameters.AddWithValue("@XmlData", XmlData);
MyCommand.Parameters.AddWithValue("@ThemeMemo", ThemeMemo);
int RowAffected = MyCommand.ExecuteNonQuery();
if (RowAffected > 0) { MessageBox.Show("新增-保存成功"); }

  ⑵Modify template

string UpdateSql = $"UPDATE InputThemeXml SET F02=@XmlData,F03=@ThemeMemo WHERE F01=@ThemeName";
SqlCommand MyCommand1 = new SqlCommand(UpdateSql, DBConn);
MyCommand1.Parameters.AddWithValue("@ThemeName", ThemeName);
MyCommand1.Parameters.AddWithValue("@XmlData", XmlData);
MyCommand1.Parameters.AddWithValue("@ThemeMemo", ThemeMemo);
int RowAffected1 = MyCommand1.ExecuteNonQuery();
if (RowAffected1 > 0) { MessageBox.Show("修改-保存成功"); }

  3. Preparation work
  ⑴ Prepare pictures as 16x16 PNG files, create resource files and put them into Textbox, Radio, RadioChecked (displayed when selected), Checkbox, CheckboxChecked (displayed when selected); ⑵ Define resources when the form is initialized
  .

//定义资源
MyImageList.Images.Add("Default", YQCYPRAS.Resourse.Resource1.line  as Image);
MyImageList.Images.Add("Radio",YQCYPRAS.Resourse.Resource1.radio as Image);
MyImageList.Images.Add("RadioChecked", YQCYPRAS.Resourse.Resource1.radioChecked as Image);
MyImageList.Images.Add("Checkbox", YQCYPRAS.Resourse.Resource1.checkbox as Image);
MyImageList.Images.Add("CheckboxChecked", YQCYPRAS.Resourse.Resource1.checkboxChecked as Image);
MyImageList.Images.Add("Textbox", YQCYPRAS.Resourse.Resource1.textbox as Image);
treeView1.ImageList = MyImageList;

  ⑶Event mounting

treeView1.MouseDown+= treeView1_MouseDown;
treeView1.KeyDown += treeView1_KeyDown;
treeView1.LostFocus += treeView1_LostFocus;
treeView1.NodeMouseDoubleClick+= treeView1_MouseDouleClick;

  4. Read the XML template and operate the generation of Treeview
  ⑴ Read the XML template

//创建一个Xml文档对象
XmlDocument XmlDoc = new XmlDocument();
//加载XML数据
string SelectThemeName = comboBox2.SelectedItem.ToString();
DBConn.Open();
string SqlQuery = $"SELECT F02 FROM InputThemeXml WHERE F01='{SelectThemeName}'";
SqlCommand MyCommand = new SqlCommand(SqlQuery, DBConn);
SqlDataReader MyReader = MyCommand.ExecuteReader();
if (MyReader.Read()) { XmlDoc.LoadXml(MyReader["F02"].ToString()); }
MyReader.Close();
DBConn.Close();
//获取文档的根节点
XmlNode RootNode = XmlDoc.SelectSingleNode(SelectThemeName);
//将根节点添加到treeview1控件中
TreeNode RootTreeviewNode = new TreeNode(SelectThemeName);
treeView1.Nodes.Add(RootTreeviewNode);
//递归生成Treeview
AddNodesToTreeview(RootNode, RootTreeviewNode);
treeView1.ExpandAll();
MessageBox.Show("OK");

  ⑵The key is to recursively generate Treeview, which is AddNodesToTreeview(RootNode, RootTreeviewNode);

        public void AddNodesToTreeview(XmlNode MyXmlNode,TreeNode MyTreeNode)
        {
            //遍历该节点下的所有的子节点
            foreach(XmlNode MyNode in MyXmlNode.ChildNodes)
            {
                string StrXmlNodeType = "";
                if (HasAttribute(MyNode, "type"))
                {
                    StrXmlNodeType=GetAttrValue(MyNode, "type");                    
                }
                //textBox4.Text += StrXmlNodeType + Environment.NewLine;
                //判断节点是否为Textbox(编辑框)、Radio(单选按钮)、Checkbox(复选框)
                if (StrXmlNodeType == "")
                {
                    //将子节点添加到treeview控件中
                    TreeNode ChildTreeNode = new TreeNode(MyNode.Name);
                    ChildTreeNode.ImageKey= "Default";
                    MyTreeNode.Nodes.Add(ChildTreeNode);
                    //如果该子节点下面还有子节点,就递归调用继续生成
                    if (MyNode.HasChildNodes)
                    {
                        AddNodesToTreeview(MyNode, ChildTreeNode);
                    }
                }
                else
                {
                    switch(StrXmlNodeType) {
                        case "Textbox":
                            TreeNode TextboxNode = new TreeNode(MyNode.Name);
                            TextboxNode.Tag= "Textbox";
                            TextboxNode.ImageKey= "Textbox";
                            TextboxNode.SelectedImageKey= "Textbox";
                            MyTreeNode.Nodes.Add(TextboxNode);
                            break;
                        case "Radio":
                            //单选按钮,表明子节点全部是Radio按钮
                            TreeNode ParentRadioNode=new TreeNode(MyNode.Name);
                            MyTreeNode.Nodes.Add(ParentRadioNode);
                            //添加子节点
                            SetChildNodeRadio(MyNode, ParentRadioNode);
                            break;
                        case "Checkbox":
                            //复选框
                            TreeNode ParentCheckboxNode = new TreeNode(MyNode.Name);
                            MyTreeNode.Nodes.Add(ParentCheckboxNode);
                            SetChildNodeCheckbox(MyNode, ParentCheckboxNode);
                            break;
                    }
                }
            }
        }

        public void SetChildNodeRadio(XmlNode ParentXmlNode, TreeNode ParentNode)
        {
            //遍历所有的子节点进行设置
            foreach(XmlNode ChildXmlNode in ParentXmlNode.ChildNodes)
            {
                string STemp = "";
                STemp = GetAttrValue(ChildXmlNode,"caption");
                TreeNode ChildRadioNode = new TreeNode(STemp);
                ChildRadioNode.Tag= "Radio";
                ChildRadioNode.ImageKey = "Radio";
                ParentNode.Nodes.Add(ChildRadioNode);
            }
        }

  5. Write event processing

        private void treeView1_MouseDown(object sender, MouseEventArgs e)
        {
            // 获取鼠标点击的位置
            TreeNode FocusNode = treeView1.GetNodeAt(e.Location);
            if (FocusNode != null)
            {
                // 获取鼠标点击的位置是否在节点的图标上
                TreeViewHitTestInfo hitTestInfo = treeView1.HitTest(e.Location);
                if (hitTestInfo.Location == TreeViewHitTestLocations.Image)
                {
                    // 鼠标点击了节点的图标
                    switch (FocusNode.Tag.ToString())
                    {
                        case "Radio":
                            // 取消同级节点的选中状态
                            foreach (TreeNode node1 in FocusNode.Parent.Nodes)
                            {
                                if (node1 != FocusNode)
                                {
                                    node1.ImageKey = "Radio";
                                    node1.SelectedImageKey = "Radio";
                                }
                            }
                            // 设置当前节点为选中状态
                            FocusNode.ImageKey = "RadioChecked";
                            FocusNode.SelectedImageKey = "RadioChecked";
                            break;
                        case "Checkbox":
                            if (FocusNode.ImageKey == "Checkbox")
                            {
                                FocusNode.ImageKey = "CheckboxChecked";
                                FocusNode.SelectedImageKey = "CheckboxChecked";
                            }
                            else
                            {
                                FocusNode.ImageKey = "Checkbox";
                                FocusNode.SelectedImageKey = "Checkbox";
                            }
                            break;
                        case "Textbox":
                            //System.Windows.Forms.TextBox MyTextbox=new System.Windows.Forms.TextBox();
                            //MyTextbox.Text = "请输入值:";
                            //MyTextbox.Location= new System.Drawing.Point(FocusNode.Bounds.Left+120, FocusNode.Bounds.Top -1);
                            //MyTextbox.Width= 120;
                            //MyTextbox.BorderStyle = BorderStyle.FixedSingle;
                            break;
                    }
                    treeView1.Invalidate();
                }

                if (hitTestInfo.Location == TreeViewHitTestLocations.Label)
                {
                    //点击标签
                    if ( FocusNode.Tag !=null)
                    {
                        switch (FocusNode.Tag.ToString())
                        {
                            case "Radio":
                                if (FocusNode.ImageKey == "RadioChecked")
                                {
                                    FocusNode.SelectedImageKey = "RadioChecked";
                                }
                                if (FocusNode.ImageKey == "Radio")
                                {
                                    FocusNode.SelectedImageKey = "Radio";
                                }
                                break;
                            case "Checkbox":
                                if (FocusNode.ImageKey == "Checkbox")
                                {
                                    FocusNode.SelectedImageKey = "Checkbox";
                                }
                                if (FocusNode.ImageKey == "CheckboxChecked")
                                {
                                    FocusNode.SelectedImageKey = "CheckboxChecked";
                                }
                                break;
                            case "Textbox":
                                FocusNode.BeginEdit();
                                break;
                            default: break;
                        }
                        treeView1.Invalidate();
                    }
                    
                }
            }
            }

  6. Judgment and value acquisition of XML attributes

        public Boolean HasAttribute(XmlNode MyXmlNode,string StrAttr)
        {
            //判断是否具有属性
            Boolean ReturnBool=false;
            if (MyXmlNode.Attributes != null && MyXmlNode.Attributes[StrAttr] != null)
            {
                ReturnBool=true;
            }
            return ReturnBool;
        }

        public string GetAttrValue(XmlNode MyXmlNode,string StrAttr)
        {
            //得到属性值
            string ReturnStr = "";
            if (MyXmlNode.Attributes != null && MyXmlNode.Attributes[StrAttr] != null)
            {
                    ReturnStr= MyXmlNode.Attributes[StrAttr].Value;
            }
            return ReturnStr;
        }

  There are several ways to generate Treeview from XML. The most troublesome method is to inherit Treeview and then rewrite it. This can achieve all the functions you want. What is slightly more troublesome is to obtain the node position and dynamically generate the input component according to the user's needs and place it in the corresponding As for the location, I took the simplest method and changed the image file of the node to meet the needs of the user.

  Issues that need attention:
  ⑴. The imageKey and SelectimageKey of the node are respectively the image displayed normally by the node and the image when the node is selected;
  ⑵. Clicking on the image and clicking the text label of the node must be processed separately;
  ⑶. The processing of Radio is the same level only. It can display one selected one, and multiple selections can be made for Checkbox;
  ⑷. The XML document and Treeview data are synchronized.

Guess you like

Origin blog.csdn.net/dawn0718/article/details/131447408