前段时间,帮朋友用C#做了一个小玩意儿,在开发过程中,发现很多用的着的东西,在网上都没有很好的解决方案,前前后后折腾了近一个月,总算是基本上完成了,在此整理下,权作以后再用到时复习之用。
这个东西有点像星座性格测试那种的,只不过是要C/S的,安装到客户端上,所以做起来限制比较多。首先要有数据录入的功能,提供界面,用户要能向其中录入数据,比如星座测试一条一条的题目;然后要对每个题目,提出相应的反馈、建议;最后,录入完成了,用户还要能够有个界面对指定的数据库进行增删改查:前面是录入的功能。在用户性格测试的时候,要有窗口完成答题,并在提交后,查看测试的结果,有打分,有整体评价,并且对于那些答得不合适的,还有一些建议。
接下来,我会按不同的模块,说一说我是怎么做的。
(1)数据的存储
由于没有数据库管理系统的支持,我选择XML来保存数据。所以,这一模块就是基本的XML的创建、添加、删除。
(1.1)XML文件的新建
我做的这个玩意儿,用的XML的数据格式比较固定,所以,新建XML文件的时候,大的结构就写死了,不希望,也不会发生改变:
2 this ._xDoc = new XmlDocument();
3 this ._xDoc.LoadXml(
4 " <?xml version=\"1.0\" encoding=\"gb2312\" ?> " +
5 " <root> " +
6 " <Principles> " +
7 &上海企业网站设计与制作nbsp; " </Principles> " +
8 " <Results> " +
9 " </Results> " +
10 " </root> "
11 );
12 try
13 {
14 this ._xDoc.Save(fileName);
15 }
16 catch (Exception ex)
17 {
18 MessageBox.Show(ex.Message);
19 }
(1.2)向XML文件中的指定位置添加节点
这里要说的是,我要添加的节点的数据结构是<ID,Content,Suggestion>。再者,添加节点的时候,用在树上直接找的办法,比较笨,用xPath会好很多,可惜时间紧没学明白……
2 {
3 XmlNode Term = this ._xDoc.CreateNode(XmlNodeType.Element, " Term " , "" );
4
5 XmlElement ID = this ._xDoc.CreateElement( " ID " );
6 ID.InnerText = id;
7 Term.AppendChild(ID);
8
9 XmlElement Content = this ._xDoc.CreateElement( " Content " );
10 Content.InnerText = content;
11 Term.AppendChild(Content);
12
13 XmlElement Suggestion = this ._xDoc.CreateElement( " Suggestion " );
14 Suggestion.InnerText = suggestion;
15 Term.AppendChild(Suggestion);
16
17 this ._xDoc.ChildNodes.Item( 1 ).ChildNodes.Item( 0 ).AppendChild(Term);
18
19 try
20 {
21 this ._xDoc.Save( this ._fileName);
22 }
23 catch (Exception ex)
24 {
25 MessageBox.Show(ex.Message);
26 }
27 }
(1.3)从XML文件中删除指定的节点
在应用中,我是在ListView中把XML的数据打出来,通过勾选CheckBox选定删除的对象。
2 {
3 XmlDocument xDoc = new XmlDocument();
4 xDoc.Load( this ._fileName);
5 foreach (ListViewItem lItem in Listview1.Items)
6 {
7 if (lItem.Checked == true )
8 {
9 // int index = Convert.ToInt32(lItem.SubItems[1].Text, 10);
10 foreach (XmlNode xNode in xDoc.ChildNodes.Item( 1 ).ChildNodes.Item( 0 ).ChildNodes)
11 {
12 if (String.Compare(xNode.ChildNodes[ 0 ].InnerText, lItem.SubItems[ 1 ].Text) == 0 )
13 {
14 xDoc.ChildNodes.Item( 1 ).ChildNodes.Item( 0 ).RemoveChild(xNode);
15 }
16 }
17 Listview1.Items.Remove(lItem);
18 }
19 }
20 xDoc.Save( this ._fileName);
21 Re_Load();
22 }
(2)动态界面生成
这个算是我在第一阶段遇到的最大的一个问题。作为一个C#的菜鸟,习惯了拖拖拽拽弄出一个窗口界面,当被要求根据用户输入,动态生成界面的时候,直接歇菜了……
在网上找了很多,可惜很多都不适用,忘记后来是在哪里找到的答案,向那位记不起名儿的童鞋致敬了。
是这样的,所谓的动态生成,就是把原来在Form.Designer.cs中代码,搬到你自己的代码中去。比如,你原来在Form.Designer.cs中有这样的代码
2 // button1
3 //
4 this .button1.Location = new System.Drawing.Point( 57 , 97 );
5 this .button1.Name = " button1 " ;
6 this .button1.Size = new System.Drawing.Size( 75 , 23 );
7 this .button1.TabIndex = 0 ;
8 this .button1.Text = " button1 " ;
9 this .button1.UseVisualStyleBackColor = true ;
你可以写到你自定义的Button2的Click事件中,这样,在你点击Button2后,就会在窗口上新加一个Button1出来
2 {
3 //
4 // button1
5 //
6 this .button1.Location = new System.Drawing.Point( 57 , 97 );
7 this .button1.Name = " button1 " ;
8 this .button1.Size = new System.Drawing.Size( 75 , 23 );
9 this .button1.TabIndex = 0 ;
10 this .button1.Text = " button1 " ;
11 this .button1.UseVisualStyleBackColor = true ;
12 this .Controls.Add( this .button1);
13 this .ResumeLayout( false );
14 }
(2.1)说一说我自己做的那个东西,我设计如下:在Form中先放好一个大Panel,然后,根据用户输入,动态加入指定个数的组件Component。在每个Component里面,包含一个GroupBox,三个Label,三个TextBox,还有一些坐标的参数。
要说一下,窃以为,动态加入组件,最麻烦的就是算坐标。那么多的东西,你需要事先把每个组件的坐标位置和大小都算好了,然后,你才可以保证你按下“添加”之后,你的组件能按照你想要的方式,呈现在窗口上。所以我对应每一条要添加的数据项,构造了上面的一个Component,然后给每个Component设置索引值,只要得到索引值,那么,这个Component的位置也就确定了。
比较欣慰的是,这个组件的坐标是按相对位置计算的:你设置GroupBox的坐标时,你只要算好你在Panel中的位置就可以了,你不用管Panel在Form的哪里。同样,你的Label,TextBox只要算好在一个200*50的GroupBox中的位置就可以了,剩下的你就不用管了。或许是以前没有注意过这个问题,反正我觉得这一性质在我做的过程中,省了不少的事儿。
这就完了么?No,还有一个我开始都没注意到的问题:最大化。对,你算的坐标是死的,当用户点击“最大化”按钮后,你的界面就会面目全非,所以,这里又要加入一个新的东西:TableLayoutPanel。Yes,需要把前面的那些写死的坐标,都放到这个TableLayoutPanel里面来,设置好每个组件的位置,这样,在“最大化”之后,依然能够保持良好的布局。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace app01_Generate
{
class Component
{
#region 成员变量定义
public static int OFFSET = 3 ;
public static int HEIGHT = 98 ;
private int _weight;
private int _index;
private GroupBox _gb;
private Label _lb1, _lb2, _lb3;
private TextBox _tb1, _tb2, _tb3;
private TableLayoutPanel _tlp;
#endregion
public Component( int index, int weight)
{
this ._index = index;
this ._weight = weight;
this ._gb = new GroupBox();
this ._gb.Location = new Point( 3 , OFFSET + this ._index * HEIGHT);
this ._gb.Size = new System.Drawing.Size( this ._weight, 92 );
this ._gb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this ._tlp = new TableLayoutPanel();
this ._tlp.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this ._tlp.ColumnCount = 25 ;
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.ColumnStyles.Add( new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 4F));
this ._tlp.Location = new System.Drawing.Point( 6 , 20 );
this ._tlp.Name = " _tlp " ;
this ._tlp.RowCount = 1 ;
this ._tlp.RowStyles.Add( new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this ._tlp.Size = new System.Drawing.Size( this ._weight - 12 , 66 );
this ._lb1 = new Label();
this ._lb1.Anchor = ((System.Windows.Forms.AnchorStyles)(( System.Windows.Forms.AnchorStyles.Right)));
this ._lb1.AutoSize = true ;
this ._tlp.SetColumnSpan( this ._lb1, 2 );
this ._lb1.Font = new System.Drawing.Font( " 微软雅黑 " , 10.5F , System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, (( byte )( 134 )));
this ._lb1.Location = new System.Drawing.Point(( int )(( this ._weight - 12 ) * 8 / 741 ), 0 );
this ._lb1.Name = " _lb1 " ;
this ._lb1.Size = new System.Drawing.Size( 47 , 19 );
this ._lb1.Text = " ID " ;
this ._lb2 = new Label();
this ._lb2.Anchor = ((System.Windows.Forms.AnchorStyles)(( System.Windows.Forms.AnchorStyles.Right)));
this ._lb2.AutoSize = true ;
this ._tlp.SetColumnSpan( this ._lb2, 2 );
this ._lb2.Font = new System.Drawing.Font( " 微软雅黑 " , 10.5F , System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, (( byte )( 134 )));
this ._lb2.Location = new System.Drawing.Point(( int )(( this ._weight - 12 ) * 124 / 741 ), 0 );
this ._lb2.Name = " _lb2 " ;
this ._lb2.Size = new System.Drawing.Size( 47 , 38 );
this 上海闵行企业网站设计与制作"color: #000000;">._lb2.Text = " Content " ;
this ._lb3 = new Label();
this ._lb3.Anchor = ((System.Windows.Forms.AnchorStyles)(( System.Windows.Forms.AnchorStyles.Right)));
this ._lb3.AutoSize = true ;
this ._tlp.SetColumnSpan( this ._lb3, 2 );
this ._lb3.Font = new System.Drawing.Font( " 微软雅黑 " , 10.5F , System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, (( byte )( 134 )));
this ._lb3.Location = new System.Drawing.Point(( int )(( this ._weight - 12 ) * 501 / 741 ), 0 );
this ._lb3.Name = " _lb3 " ;
this ._lb3.Size = new System.Drawing.Size( 47 , 38 );
this ._lb3.Text = " Suggestion " ;
this ._tb1 = new TextBox();
this ._tb1.Anchor = ((System.Windows.Forms.AnchorStyles)((( System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this ._tlp.SetColumnSpan( this ._tb1, 2 );
this ._tb1.Font = new System.Drawing.Font( " 仿宋 " , 10.5F , System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, (( byte )( 134 )));
this ._tb1.Location = new System.Drawing.Point(( int )(( this ._weight - 12 ) * 61 / 741 ), 3 );
this ._tb1.Name = " _tb1 " ;
this ._tb1.Size = new System.Drawing.Size( 52 , 29 );
this ._tb2 = new TextBox();
this ._tb2.Anchor = ((System.Windows.Forms.AnchorStyles)((( System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this ._tlp.SetColumnSpan( this ._tb2, 11 );
this ._tb2.Font = new System.Drawing.Font( " 仿宋 " , 10.5F , System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, (( byte )( 134 )));
this ._tb2.Location = new System.Drawing.Point(( int )(( this ._weight - 12 ) * 177 / 741 ), 3 );
this ._tb2.Multiline = true ;
this ._tb2.Name = " _tb2 " ;
this ._tb2.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this ._tb2.Size = new System.Drawing.Size( 313 , 48 );
this ._tb3 = new TextBox();
this ._tb3.Anchor = ((System.Windows.Forms.AnchorStyles)((( System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this ._tlp.SetColumnSpan( this ._tb3, 6 );
&n上海徐汇企业网站设计与制作bsp; this ._tb3.Font = new System.Drawing.Font( " 仿宋 " , 10.5F , System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, (( byte )( 134 )));
this ._tb3.Location = new System.Drawing.Point(( int )(( this ._weight - 12 ) * 554 / 741 ), 3 );
this ._tb3.Multiline = true ;
this ._tb3.Name = " _tb3 " ;
this ._tb3.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this 上海徐汇企业网站制作="color: #000000;">._tb3.Size = new System.Drawing.Size( 184 , 48 );
this ._tlp.Controls.Add( this ._lb1, 0 , 0 );
this ._tlp.Controls.Add( this ._tb1, 2 , 0 );
this ._tlp.Controls.Add( this ._lb2, 4 , 0 );
this ._tlp.Controls.Add( this ._lb3, 17 , 0 );
this ._tlp.Controls.Add( this ._tb3, 19 , 0 );
this ._tlp.Controls.Add( this ._tb2, 6 , 0 );
this ._gb.Controls.Add( this ._tlp);
}
public void addToPanel( ref Panel pnl)
{
pnl.Controls.Add( this ._gb);
}
public void Clear()
{
this ._tb1.Clear();
this ._tb2.Clear();
this ._tb3.Clear();
}
public string getID()
{
return this ._tb1.Text.Trim();
}
public string getContent()
{
return this ._tb2.Text.Trim();
}
public string getSuggestion()
{
return this ._tb3.Text.Trim();
}
public bool Check()
{
if ( string .IsNullOrEmpty( this ._tb1.Text.Trim()) == false ||
string .IsNullOrEmpty( this ._tb2.Text.Trim()) == false ||
string .IsNullOrEmpty( this ._tb3.Text.Trim()) == false
)
return false ;
else
return true ;
}
public void Refresh( string id, string content, string suggestion)
{
this ._tb1.Text = id;
this ._tb2.Text = content;
this ._tb3.Text = suggestion;
}
}
}
(3)ListView的使用
不得不说,ListView真是个不错的东西,在显示数据和处理的时候,非常的简单实用。
(3.1)ListView显示XML数据
原理很简单,就是把XML中每个节点,填充到ListView的SubItem上。
2 {
3 this .Listview1.Columns.Clear();
4 this .Listview1.Items.Clear();
5 this .Listview1.Columns.Add( " " , 20 , HorizontalAlignment.Left);
6 this .Listview1.Columns.Add( " ID " , 80 , HorizontalAlignment.Left);
7 this .Listview1.Columns.Add( " Content " , ( int )(( this .Listview1.Width - 80 ) * 0.5 ), HorizontalAlignment.Left);
8 this .Listview1.Columns.Add( " Suggestion " , ( int )(( this .Listview1.Width - 80 ) * 0.3 ), HorizontalAlignment.Left);
9 this .Listview1.ListViewItemSorter = new ListViewItemComparer( 1 );
10
11 ListViewItem myItem = null ;
12 XmlDocument xDoc = new XmlDocument();
13 xDoc.Load( this ._fileName);
14 XmlNode root = xDoc.ChildNodes.Item( 1 ).ChildNodes.Item( 0 );
15
16 foreach (XmlNode xNode in root.ChildNodes)
17 {
18 myItem = new ListViewItem();
19 // myItem.SubItems.Add("");
20 myItem.SubItems.Add(xNode.ChildNodes[ 0 ].InnerText);
21 myItem.SubItems.Add(xNode.ChildNodes[ 1 ].InnerText);
22 myItem.SubItems.Add(xNode.ChildNodes[ 2 ].InnerText);
23 Listview1.Items.Add(myItem);
24 }
25
26 }
(3.2)ListView的排序
注意到,上面设置了ListView的排序规则"this.Listview1.ListViewItemSorter = new ListViewItemComparer(1);",意思是:用ListViewItemComparer的一个对象,按ListView的第一列数据进行排序,就是按照ID进行排序。我是这儿考虑的,在XML文件里面,你对子节点按照ID进行排序,又麻烦,而且意义不是很大,干脆在呈现数据的时候,排一次序,这样看起来就非常齐整,不会因为用户的增加删除而乱序。
2 {
3 private int col;
4 public ListViewItemComparer()
5 {
6 col = 0 ;
7 }
8 public ListViewItemComparer( int column)
9 &nb上海闵行企业网站制作sp; {
10 col = column;
11 }
12 public int Compare( object x, object y)
13 {
14 return Convert.ToInt32(((ListViewItem)x).SubItems[col].Text, 10 ) - Convert.ToInt32(((ListViewItem)y).SubItems[col].Text, 10 );
15 }
16 }
(3.3)ListView的删除
发现了ListView.CheckBoxes这个属性,设置为true之后,在每条数据的前面加上了一个CheckBox,实用这个东西还完成数据项的删除,同时映射后ListView绑定的XML文件数据删除。
2 xDoc.Load( this ._fileName);
3 foreach (ListViewItem lItem in Listview1.Items)
4 {
5 if (lItem.Checked == true )
6 {
7 // int index = Convert.ToInt32(lItem.SubItems[1].Text, 10);
8 foreach (XmlNode xNode in xDoc.ChildNodes.Item( 1 ).ChildNodes.Item( 0 ).ChildNodes)
9 {
10 if (String.Compare(xNode.ChildNodes[ 0 ].InnerText, lItem.SubItems[ 1 ].Text) == 0 )
11 {
12 xDoc.ChildNodes.Item( 1 ).ChildNodes.Item( 0 ).RemoveChild(xNode);
13 }
14 }
15 Listview1.Items.Remove(lItem);
16 }
17 }
18 xDoc.Save( this ._fileName);
19 Re_Load();
可能,这些操作用DataGridView比较好,不过,时间有点急,DataGridView的东西有比较多,实在是没能吃下,用了下,比较吃力,还是暂时放弃了。