花費了十天時間,為公司開發了一套簡單的網絡版的信息管理系統,功能主要有客戶信息管理,員工信息管理,常用信息管理(各種信函打印、常用網址/常用電話等),公司簡單的財務管理等。把一些點點滴滴的技巧在此記錄下來,以備查用。
1.數據綁定。 DataReader 讀取數據,用DataTable.Load(IDataReader)方法將數據加載到 DataTable ,用DataGridView 顯示輸出。不要把DataGridVIEw直接綁定到DataReader的目的是數據導出到Excel時,數據源可以再次從DataGridVIEw獲得。
不要在 DataGridVIEw 內編輯添加數據,因為數據類型檢查不嚴格(或要嚴格檢查類型需要花費更大的成本)。
2.數據導出到 Excel 。代碼如下:
注意:Excel的Cells[,]下標是從1,1開始的,而不是0,0。
3.防止子窗口重復打開,確保某一子窗口只打開一次。代碼為:
foreach (Form frm in this.MdiChildren)
...{
if (frm is WorkerList)
...{
frm.WindowState = FormWindowstate.Normal;
frm.Activate();
return;
}
}
WorkerList wl = new WorkerList();
wl.MdiParent = this;
wl.Show();
4.使用枚舉 enum 區分類同信息。
硬編碼方式容易造成混亂。如本系統的常用電話/常用網址,數據項都為:名稱-內容-備注,可將它們保存在同一個表中,在程序中為區分信息類型,可定義以下枚舉:
public enum TelWeb
...{
Telephone,WebSite
}
5.在ToolStrip中加入其它WinForm控件。
如在ToolStrip中加入DateTimePicker。如圖:
DateTimePicker dt1 = new DateTimePicker();
dt1.Width = 110;
ToolStripControlHost host1 = new ToolStripControlHost(dt1);
host1.Alignment = ToolStripItemAlignment.Right;
toolStrip1.Items.Insert(10, host1);
6.用微軟的可打印的富文本框控件打印帶格式的文本。
與.NetFX自帶的RichTextBox相比只增強了打印功能。通過該控件,可設置文本字體、顏色、對齊方式、粘貼圖片,可打印看上去很專業的文檔,截圖如下:
7.保存富文本格式到數據庫。
以二進制格式保存。保存的代碼為:
MemoryStream ms = new MemoryStream();
rtbContent.SaveFile(ms, RichTextBoxStreamType.RichText);
byte[] bt=ms.ToArray(); //將bt保存到數據庫
讀取的代碼為:
byte[] bt = (byte[])SqlHelper.ExecuteScalar(sqlStr, null);
MemoryStream ms = new MemoryStream(bt, false);
rtbContent.LoadFile(ms, RichTextBoxStreamType.RichText);
在SQLServer中對應的數據類型為:image
8.管理員權限控制。
管理員信息表中權限字段保存一個字符串,擁有該項權限則在字符串相應位置保存為1,沒有該項權限為0。在管理員登錄時判斷權限,啟用或禁用相應的菜單項。
9.信息分類。
如客戶分類分為:軟件客戶、網站客戶、合作客戶等。如果數據量不是太大,可不用單獨建立分類表,在添加的時候,客戶類型。可用ComboBox,在Form加載時檢索數據庫中已有的客戶類型填充到ComboBox中。這樣可選擇已有客戶類型,也可以添加新的客戶類型。
10.數據庫安裝。
不必集成在安裝包中,可單獨寫一個WinForm程序來收集連接服務器的信息(服務器地址、數據庫名、用戶名、密碼等),並執行數據庫生成的腳本來建立數據表,視圖,存儲過程、索引等。
讀取保存數據庫腳本文件的代碼:
public static string ReadDBScript(string fileName)
...{
StreamReader sr = new StreamReader(fileName);
return sr.ReadToEnd();
}
注意:數據庫生成的腳本必須把"GO"去掉,否則執行時報錯。
11.安全控制。
由於是網絡版系統,因而安全性要考慮周全。數據庫連接字符串加密保存在配置文件中。為了防止軟件XCopy到其它機器中,可以取機器的硬件(如硬盤、網卡、CPU)序列號的一部分再加上自己的私有密鑰作為連接字符串的加密密鑰(八位ASCII),確保密鑰的私密性、每機器唯一性。
(1)取得機器CPU的ID的前八位作為密鑰:
public static string GetProcessID()
...{
try
...{
string str = string.Empty;
ManagementClass mcCpu = new ManagementClass("win32_Processor");
ManagementObjectCollection mocCpu = mcCpu.GetInstances();
foreach (ManagementObject m in mocCpu)
...{
str = m["ProcessorId"].ToString().Trim().Substring(0, 8);
}
return str;
}
catch (Exception ex)
...{
return "zhenxing"; //如果失敗取默認的密鑰
}
}
(2)加密算法:
public static string Encode(string data)
...{
byte[] aKey = System.Text.ASCIIEncoding.ASCII.GetBytes(GetProcessID());
byte[] aIV = System.Text.ASCIIEncoding.ASCII.GetBytes(GetProcessID());
DESCryptoServiceProvider cp = new DESCryptoServiceProvider();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, cp.CreateEncryptor(aKey, aIV), CryptoStreamMode.Write);
StreamWriter sw = new StreamWriter(cs);
sw.Write(data);
sw.Flush();
cs.FlushFinalBlock();
sw.Flush();
return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
}
(3)解密算法:
public static string Decode(string data)
...{
byte[] aKey = System.Text.ASCIIEncoding.ASCII.GetBytes(GetProcessID());
byte[] aIV = System.Text.ASCIIEncoding.ASCII.GetBytes(GetProcessID());
byte[] Enc;
try
...{
Enc = Convert.FromBase64String(data);
}
catch
...{
return null;
}
DESCryptoServiceProvider cp = new DESCryptoServiceProvider();
MemoryStream ms = new MemoryStream(Enc);
CryptoStream cs = new CryptoStream(ms, cp.CreateDecryptor(aKey, aIV), CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
(4)數據庫連接字符串保存到配置文件:
public static void SaveToConfig(string connStr)
...{
XmlDocument doc = new XMLDocument();
string fn = "zxjay.exe.config";
doc.Load(fn);
XMLNodeList nodes = doc.GetElementsByTagName("add");
for (int i = 0; i < nodes.Count; i++)
...{
XMLAttribute att = nodes[i].Attributes["key"];
if (att.Value == "SQLConectionString")
...{
att = nodes[i].Attributes["value"];
att.Value = connStr;
break;
}
}
doc.Save(fn);
}