프로젝트의 데이터 테이블은 아직 확정되지 않았지만,
1. 상대적으로 복잡하고 변경될 수 있다는 점,
2. 입력 항목이 유사하기 때문에 대부분의 항목을 선택했다는 점,
3. 애플리케이션이 C 언어라는 점은 확실하다. /S 양식 응용 프로그램입니다.
이러한 사용자 요구에 따라 사용자가 기능적 효과를 빠르게 볼 수 있도록 하기 위해 XML을 Treeview와 결합하여 사용할 수 있습니다.
최종 입력 렌더링:
위 그림을 구현하기 위해 완료해야 할 작업은 다음과 같습니다.
1. XML 파일 정의
<事故调查 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. XML 파일을 데이터 수집 템플릿과 데이터베이스에 저장합니다. 데이터 입력이 필요할 때 읽을 수 있습니다.
⑴새 템플릿 추가
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("新增-保存成功"); }
⑵템플릿 수정
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. 준비 작업
⑴ 사진을 16x16 PNG 파일로 준비하고 리소스 파일을 생성하여 Textbox, Radio, RadioChecked(선택 시 표시), Checkbox, CheckboxChecked(선택 시 표시)에 넣습니다 ⑵ 폼 초기화 시 리소스를 정의합니다
.
//定义资源
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;
⑶이벤트 마운팅
treeView1.MouseDown+= treeView1_MouseDown;
treeView1.KeyDown += treeView1_KeyDown;
treeView1.LostFocus += treeView1_LostFocus;
treeView1.NodeMouseDoubleClick+= treeView1_MouseDouleClick;
4. XML 템플릿 읽기 및 Treeview 생성 작업
⑴ XML 템플릿 읽기
//创建一个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");
⑵핵심은 AddNodesToTreeview(RootNode, RootTreeviewNode)인 Treeview를 반복적으로 생성하는 것입니다.
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. 이벤트 처리 쓰기
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. XML 속성의 판단 및 가치 획득
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;
}
XML에서 Treeview를 생성하는 방법에는 여러 가지가 있습니다. 가장 번거로운 방법은 Treeview를 상속받은 다음 다시 작성하는 것입니다. 이렇게 하면 원하는 모든 기능을 얻을 수 있습니다. 약간 더 번거로운 것은 노드 위치를 얻고 그에 따라 입력 구성 요소를 동적으로 생성하는 것입니다. 위치는 가장 간단한 방법을 취하고 사용자의 요구에 맞게 노드의 이미지 파일을 변경했습니다.
주의사항 :
⑴.노드의 imageKey와 SelectimageKey는 각각 노드에서 정상적으로 표시되는 이미지와 노드를 선택했을 때의 이미지이며,
⑵.이미지 클릭과 노드의 텍스트 라벨 클릭은 별도로 처리해야 함 ;
⑶. Radio 처리는 동일한 수준으로만 처리되며 선택된 하나만 표시할 수 있고 Checkbox는 다중 선택이 가능합니다 ⑷.
XML 문서와 Treeview 데이터가 동기화됩니다.