【小记】:最近基于WinForm+Access数据库完成一个法律咨询管理系统。本系统要求类似网页后台管理效果,并且基于局域网内,完成多客户端操作同一数据库,根据权限不同分别执行不同功能模块。核心模块为级联统计类型管理、数据库咨询数据扇形统计、树的操作、咨询数据的管理、手写分页、Excel数据的导出、多用户操作服务器数据等。并支持多用户同时操作,远程连接数据库且对数据IP信息的修改。开发过程中特别对界面的要求和事后多用户操作显得略为麻烦。自此,本项目得以完善交付,然后对其进行小结。依旧采用整个框架认识,核心知识逐个梳理分析,以便于二次开发和需要之程序员共享。
篇一:WinForm开发总体概述与技术实现
【开篇】运行效果图示和功能介绍
1 登陆信息图示和功能概述
注解:本登陆界面可实现远程连接数据库,点击:服务器设置窗体进行向下展开,在IP地址配置处输入正确的IP地址(前提需要远程连接服务器)。其原理为,App.config文件进行远程连接数据库配置,通过连接IP地址下共享文件夹中的Access数据文件访问。具体远程实现代码在篇二进行展开。并且通过对App.config文件操作进行IP地址的本地保存。
2 主窗体功能模块图示与功能概述
注解:管理员登陆进入主页面可以实现对系统的咨询管理、打印用户报表和咨询报表、对多组合数据扇形图的实现、用户管理、咨询类型级联修改和删除、以及个人信息的修改。律师进入页面后只能对我要咨询操作。整个数据控件的显示效果和布局方式,手写分页、以及如何实现类似网页版效果,后面逐步解析。
【总结】核心知识点梳理
1 如何实现窗体折叠效果?如何读取连接字符串的IP地址?
if (this.Height == 325)
{
button2.Text = "服务器设置 ↑";
this.Height = 465;
}
else
{
button2.Text = "服务器设置 ↓";
this.Height = 325;
}
注:通过设置窗体高度和文本信息进行折叠
//把连接数据库的字符串分割,并填充至文本框
try
{
XDocument doc = XDocument.Load(file);
//Provider=Microsoft.ACE.OLEDB.12.0;Data Source=//10.130.16.136/db/Legal.accdb
string connstring = doc.Elements("configuration").Elements("connectionStrings").Elements("add").Attributes("connectionString").FirstOrDefault().Value;
string[] array1 = connstring.Split(';');
string str = array1[1].Split('=')[1];// ->//10.130.16.136/db/Legal.accdb
string[] newarray = str.Split('/');
this.textBox3.Text = newarray[2].Split('/')[0].ToString();
}
catch { }
注:通过操作App.config文件,并且进行字符串截取获取IP地址
-------------------------------------------------------------------------------------------------------------------------------------------------------
2 如何进行连接远程数据库IP地址的设置与保存?
if (textBox3.Text != "")
{
string file = @"C:\db\App.config";
XDocument doc = XDocument.Load(file);
//sql数据库数据库配置
//string connstring = "initial catalog=Highway;Data Source=" + this.textBox3.Text + ";u;
//access数据库远程配置
//Provider=Microsoft.ACE.OLEDB.12.0;Data Source=//10.130.16.136/db/Legal.accdb
string connstring = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=//" + textBox3.Text.ToString()+ "/db/Legal.accdb";
doc.Elements("configuration").Elements("connectionStrings").Elements("add").Attributes("connectionString").FirstOrDefault().SetValue(connstring);
doc.Save(file);
//由于DBHelperSQL中的ConnectionString(公共静态变量)未被修改引发的bug
XDocument xdoc = XDocument.Load(file);
string val = doc.Elements("configuration").Elements("connectionStrings").Elements("add").Attributes("connectionString").FirstOrDefault().Value;
SQLHelper.connstr = val;
}
注:在文本框中修改IP地址,然后通过操作本地App.config文件,进行修改保存操作。但是保存后要及时修改配置连接字符串中的数据。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 如何进行窗体间传值?
子窗体:
if (dt.Rows[0][1].ToString() == textBox1.Text.ToString() && dt.Rows[0][2].ToString() == textBox2.Text.ToString()) { int id = Convert.ToInt32(dt.Rows[0]["ID"].ToString()); string type = dt.Rows[0][3].ToString(); string name = this.textBox1.Text.ToString(); ; this.Hide(); Fm_Main fm = new Fm_Main(id, name, type); fm.Show(); this.Hide(); }
父窗体:
#region 构造函数接收用户名、管理权限
private string Name;
private string Type;
private int ID;
public Fm_Main() { }
public Fm_Main(int id,string name, string type)
{
InitializeComponent();
this.Name = name;
this.Type = type;
this.ID = id;
}
#endregion
注:在服父窗体写个构造函数,并且定义其属性,然后传参赋值即可。但是在构造函数中添加如下语句: InitializeComponent();否则运行不是自己预期的效果。
4 父窗体如何作为容器,显示子窗体?
//绘制的方式OwnerDrawFixed表示由窗体绘制大小也一样
this.tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
this.tabControl1.Padding = new System.Drawing.Point(CLOSE_SIZE, CLOSE_SIZE);
this.tabControl1.DrawItem +=new DrawItemEventHandler(tabControl1_DrawItem);
this.tabControl1.MouseDown += new MouseEventHandler(tabControl1_MouseDown);
#region 绘制tabControl的关闭按钮,以及关闭功能的实现 private void tabControl1_DrawItem(object sender, DrawItemEventArgs e) { try { Rectangle myTabRect = this.tabControl1.GetTabRect(e.Index); //先添加TabPage属性 e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, this.Font, SystemBrushes.ControlText, myTabRect.X + 4, myTabRect.Y + 4); //再画一个矩形框 using (Pen p = new Pen(Color.White)) { myTabRect.Offset(myTabRect.Width - (CLOSE_SIZE + 3), 2); myTabRect.Width = CLOSE_SIZE; myTabRect.Height = CLOSE_SIZE; e.Graphics.DrawRectangle(p, myTabRect); } //填充矩形框 Color recColor = e.State == DrawItemState.Selected ? Color.White : Color.White; using (Brush b = new SolidBrush(recColor)) { e.Graphics.FillRectangle(b, myTabRect); } //画关闭符号 using (Pen objpen = new Pen(Color.Black)) { //使用图片 Bitmap bt = new Bitmap(image); Point p5 = new Point(myTabRect.X, 4); e.Graphics.DrawImage(bt, p5); //e.Graphics.DrawString(this.MainTabControl.TabPages[e.Index].Text, this.Font, objpen.Brush, p5); } e.Graphics.Dispose(); } catch (Exception) { } } //鼠标作用事件设置 void tabControl1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { int x = e.X, y = e.Y; //计算关闭区域 Rectangle myTabRect = this.tabControl1.GetTabRect(this.tabControl1.SelectedIndex); myTabRect.Offset(myTabRect.Width - (CLOSE_SIZE + 3), 2); myTabRect.Width = CLOSE_SIZE; myTabRect.Height = CLOSE_SIZE; //如果鼠标在区域内就关闭选项卡 bool isClose = x > myTabRect.X && x < myTabRect.Right && y > myTabRect.Y && y < myTabRect.Bottom; if (isClose == true) { this.tabControl1.TabPages.Remove(this.tabControl1.SelectedTab); } } } const int CLOSE_SIZE = 15; //tabPage标签图片 Bitmap image = new Bitmap(@"C:\db\btnClose.png"); #endregion