C#程式設計的小技巧,小歐ou所解的簡單問題或者程式觀念會寫在這邊,持續不斷更新
前言 : 一直都很想把常用的C#技巧整理出來,讓像我ㄧ樣的菜鳥遇到問題時,可以有個參考的地方,。
目錄
4. 點選表單右上角關閉按鈕時,出現是否確認關閉的訊息視窗。
9. 取得系統特殊資料夾目錄路徑,透過Environment.SpecialFolder。
10. TextBox 與 RichTextBox 斷行(下一行)。
12. 程式好像當住或控制項內的值無法即時更新的懶人解決方式。
13. RichTextBox使用FontDialog改變字型。
15. 透過 OpenFileDialog 選取 txt 檔,並將txt檔的資料內容顯示在 TextBox 中。
18. 客製化格式 DateTimePicker 只有時間,並且使用微調方塊來設定時間。
20. 讓 TextBox1 到 TextBox10 的Text 值為 1 到 10 ( this.Controls 的應用 )。
22. VB有isNumeric判斷是否可轉換為數值,C#有TryParse做字串轉數值並回傳轉換是成功或是失敗。
27. 設定兩個或兩個以上的字型樣式 (例如一段文字設定粗體加斜體)。
31. StreamReader 讀取時,中文字部分變成亂碼的解決方法。
33. String 轉為 Byte 序列與 Byte 序列轉為 String。
34. 更改 SplitContainer 面板的配置為水平或垂直方向。
37. 加入控制項到 Form、FlowLayoutPanel、GroupBox、Panel 中。
38. 善用 SqlException,讓資料庫錯誤訊息更明確。
39. 出現錯誤 [ 不會傳回任何重要資料行資訊的 SelectCommand 不支援 UpdateCommand 動態 SQL 的產生 ] 解決方式。
40. 程式中使用到 unsafe,出現 [ 程式中若有 unsafe 程式碼,編譯時必須使用 /unsafe 選項 ] 解決方式。
41. 出現錯誤 [ 找不到型別或命名空間名稱 'ManagementObject' ] 解決方式。
42. 在沒有 Visual Studio 的電腦環境下,如何註冊 DLL。
this.listBox1.Items.AddRange(FontFamily.Families);
執行結果
this.Text = string.Empty;
this.ControlBox = false;
執行結果
this.ShowInTaskbar = false;
4. 點選表單右上角關閉按鈕時,出現是否確認關閉的訊息視窗。
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_CLOSE = 0xF060;
if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE)
{
// 顯示MessageBox
DialogResult Result = MessageBox.Show("確定關閉表單", "表單訊息", MessageBoxButtons.YesNo);
if (Result == System.Windows.Forms.DialogResult.Yes)
{
// 關閉Form
this.Close();
}
else
{
return;
}
}
base.WndProc(ref m);
}
執行結果
this.WindowState = FormWindowState.Maximized; // 最大化
this.WindowState = FormWindowState.Minimized; // 最小化
this.WindowState = FormWindowState.Normal; // 預設大小
this.TopMost = true; // 表單最上層顯示
System.Diagnostics.Process.Start("calc.exe"); // 開啟小算盤
System.Diagnostics.Process.Start("notepad.exe"); // 開啟記事本
string str1 = "我要顯示分號\"出來";
string str2 = @"我要顯示分號""出來";
MessageBox.Show("第一種方式 : " + str1 + ", 第二種方式 : " + str2);
執行結果
string appPath = Application.ExecutablePath;
MessageBox.Show(appPath , "程式所在位置");
執行結果
9. 取得系統特殊資料夾目錄路徑,透過Environment.SpecialFolder。
以下程式碼取出 我的文件夾 位置
string MyDocumentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
MessageBox.Show(MyDocumentsPath, "我的文件夾位置");
執行結果
進階閱讀
Environment.SpecialFolder列舉型別
http://msdn.microsoft.com/zh-tw/library/system.environment.specialfolder.aspx
10. TextBox 與 RichTextBox 斷行(下一行)。
// =============== TextBox 斷行 (下一行)==================
// 使用 \r\n
textBox1.Multiline = true;
textBox1.Text = "textBox1\r\nLine One\r\nLine Two\r\n";
// 使用 string陣列
textBox2.Multiline = true;
string [] tb2 = ...{"textBox2","Line One","Line Two"};
textBox2.Lines = tb2;
// 使用 System.Environment.NewLine
textBox3.Multiline = true;
textBox3.Text = "textBox3" + System.Environment.NewLine + "Line One" + System.Environment.NewLine + "Line Two";
// 使用 StringBuilder.AppendLine
StringBuilder tb4 = new StringBuilder();
tb4.AppendLine("textBox4");
tb4.AppendLine("Line One");
tb4.AppendLine("Line Two");
textBox4.Text = tb4.ToString();
// =============== RichTextBox 斷行 (下一行)==================
// 使用 \r\n
richTextBox1.Text = "richTextBox1\r\nLine One\r\nLine Two\r\n";
// 使用 string陣列
string[] rtb2 = ...{ "richTextBox2" , "Line One", "Line Two" };
richTextBox2.Lines = rtb2;
// 使用 System.Environment.NewLine
richTextBox3.Text = "richTextBox3" + System.Environment.NewLine + "Line One" + System.Environment.NewLine + "Line Two";
// 使用 StringBuilder.AppendLine
StringBuilder rtb4 = new StringBuilder();
rtb4.AppendLine("richTextBox4");
rtb4.AppendLine("Line One");
rtb4.AppendLine("Line Two");
richTextBox4.Text = rtb4.ToString();
執行結果
DateTime.Now
利用 Timer 與 DateTime.Now 的小時鐘範例
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 100;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = DateTime.Now.ToString();
}
執行結果
12. 程式好像當住或控制項內的值無法即時更新的懶人解決方式,不想偷懶請用多執行緒或者BackGroundWork元件。
richTextBox1.Refresh(); // 方法一
richTextBox1.Update(); // 方法二
Application.DoEvents(); // 方法三;此法雖方便,但可能發生CPU使用率100%或cpu資源未釋放
System.Threading.Thread.Sleep(1) // 加上此行可稍為解決
// 可參考
// http://blogs.msdn.com/jfoscoding/archive/2005/08/06/448560.aspx
// http://goodlucky.pixnet.net/blog/post/26183258
13. RichTextBox使用FontDialog改變字型。
程式碼
private void btnChangeFont_Click(object sender, EventArgs e)
{
FontDialog fontDialog1 = new FontDialog();
if (fontDialog1.ShowDialog().Equals(DialogResult.OK))
{
// RichTextBox.SelectionFont取得目前選擇的文字,並且將FontDialog所設定的字型結果套入
richTextBox1.SelectionFont = fontDialog1.Font;
}
}
執行結果
程式碼
System.Net.IPHostEntry IPHost = System.Net.Dns.GetHostEntry(Environment.MachineName);
if (IPHost.AddressList.Length > 0)
{
MessageBox.Show(IPHost.AddressList[0].ToString(), "電腦本機IP");
}
執行結果
15. 透過 OpenFileDialog 選取 txt 檔,並將txt檔的資料內容顯示在 TextBox 中。

2

3

4

5

執行結果

2

3

4

5

6

7

執行結果

2

3

4

5

6

7

8

執行結果
18. 客製化格式 DateTimePicker 只有時間,並且使用微調方塊來設定時間

2

3

執行結果

02

03

04

05

06

07

08

09

10

11

12

13

20. 讓 TextBox1 到 TextBox10 的Text 值為 1 到 10 ( this.Controls 的應用 )。

2

3

4

5

6

7

執行結果

假如影像格式不符合時,可以使用 IrfanView 免費軟體轉檔即可
執行結果
22. VB有isNumeric判斷是否可轉換為數值,C#有TryParse做字串轉數值並回傳轉換是成功或是失敗。

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

執行結果
進階閱讀
如何使用 Visual C# 中實作 Visual Basic.NET IsNumeric 功能 FROM MSDN
http://support.microsoft.com/kb/329488/zh-tw
HOW TO:判斷字串是否表示數值 (C# 程式設計手冊) FROM MSDN
http://msdn.microsoft.com/zh-tw/library/bb384043.aspx
有些程式開啟時,會先出現一個畫面(可能是版權宣告之類的)漸出與漸入後,才進入主程式中,以下透過設定 Form.Opacity 屬性來達成
主表單 Form1

2

3

4

5

6

看板表單 Form2,顯示時先漸出,之後漸入,最後關閉

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

執行結果

2

3

菜鳥常犯的錯誤在 bool? 型別,一般在 if 判斷式搭配bool型別時,習慣使用以下程式碼

2

3

4

但使用 bool? 型別時,可包含三種不同的值:true、false 和 null。因此在 if、for 或 while 等條件式使用時可能會發生錯誤。





進階閱讀
使用可為 Null 的型別 (C# 程式設計手冊)
http://msdn.microsoft.com/zh-tw/library/2cf62fcy
以下程式碼為產生不重複的亂數的函式 MakeRnd,請注意此函式沒有防呆,例如
1. 亂數範圍的上限 > 亂數範圍的下限
2. 亂數範圍的上限 - 亂數範圍的下限 > 亂數產生的數量
有需要使用的菜鳥們請自行修改
//// <summary>
/// 產生不重複的亂數
/// </summary>
/// <param name="intLower"></param>產生亂數的範圍下限
/// <param name="intUpper"></param>產生亂數的範圍上限
/// <param name="intNum"></param>產生亂數的數量
/// <returns></returns>
private System.Collections.ArrayList MakeRand(int intLower, int intUpper, int intNum)
{
System.Collections.ArrayList arrayRand = new System.Collections.ArrayList();
Random random = new Random((int)DateTime.Now.Ticks);
int intRnd;
while (arrayRand.Count < intNum)
{
intRnd = random.Next(intLower, intUpper + 1);
if (!arrayRand.Contains(intRnd))
{
arrayRand.Add(intRnd);
}
}
return arrayRand;
}
使用範例
private void btnMakeRand_Click(object sender, EventArgs e)
{
// txtLower 為 TextBox 控制項,讓使用者輸入亂數範圍下限
// txtUpper 為 TextBox 控制項,讓使用者輸入亂數範圍上限
// txtNum 為 TextBox 控制項,讓使用者輸入亂數範圍數量
lstboxRand.Items.Clear();
System.Collections.ArrayList rnd = MakeRand(int.Parse(txtLower.Text), int.Parse(txtUpper.Text), int.Parse(txtNum.Text));
lstboxRand.Items.AddRange(rnd.ToArray());
}
執行結果
進階閱讀
Random 類別
http://msdn.microsoft.com/zh-tw/library/system.random
// 判斷檔案是否存在
string FileName = @"C:\WINDOWS\notepad.exe";
if (System.IO.File.Exists(FileName))
{
MessageBox.Show(FileName + " 存在","判斷檔案是否存在");
}
else
{
MessageBox.Show(FileName + " 不存在","判斷檔案是否存在");
}
執行結果
進階閱讀
對於檔案與資料夾操作的部份,可以參考MSDN當中的範例File 類別
File 類別
http://msdn.microsoft.com/zh-tw/library/system.io.file
27. 設定兩個或兩個以上的字型樣式 (例如一段文字設定粗體加斜體)。
假如要將一段文字,同時設定 粗體文字 FontStyle.Bold 與 斜體文字 FontStyle.Italic,則需透過 FontFamily 類別,透過 | 做連結
// 將RichTextBox中選取的文字,透過 FontFamily 類別
// 同時設定 粗體文字 FontStyle.Bold 與 斜體文字 FontStyle.Italic
Font MyFont = new Font(new FontFamily("標楷體"), 10, FontStyle.Bold | FontStyle.Italic);
this.richTextBox1.SelectionFont = MyFont;
執行結果
進階閱讀
FontFamily 類別
http://msdn.microsoft.com/zh-tw/library/system.drawing.fontfamily
this.lstSerialPort.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
執行結果
進階閱讀
SerialPort.GetPortNames 方法
http://msdn.microsoft.com/zh-tw/library/system.io.ports.serialport.getportnames.aspx
在 VB 與 C# 使用 System.IO.Ports 讀取 COM port 資料
http://www.devasp.net/net/articles/display/727.html
正則表達式的應用,判斷字串是否符合 xxxx-xxxxxx 四碼數字-六碼數字的手機號碼格式
程式碼
private void btnMatch_Click(object sender, EventArgs e)
{
System.Text.RegularExpressions.Regex rex = new System.Text.RegularExpressions.Regex("^[0-9]{4}-[0-9]{6}$");
if (rex.IsMatch(txtInput.Text))
{
MessageBox.Show("符合");
}
else
{
MessageBox.Show("不符合");
}
}
執行結果
進階閱讀
http://www.blueshop.com.tw/board/show.asp?subcde=BRD20090702212122PXQ&fumcde=
預設的DataTime格式為西元,也就是2009/2/4,假如想要轉換成98/2/4的話,可以使用CultureInfo類別,轉換不同的日期格式。
CultureInfo類別 : 提供特定文化特性 (Culture) 的相關資訊,如文化特性名稱、書寫系統、使用的行事曆,以及如何格式化日期和排序字串。
程式碼
System.Globalization.CultureInfo cuinfo = new System.Globalization.CultureInfo("zh-TW");
cuinfo.DateTimeFormat.Calendar = cuinfo.OptionalCalendars[2];
MessageBox.Show(DateTime.Now.ToString("yyyy/MM/dd", cuinfo));
執行結果
進階閱讀
[C#][VB.NET]西元轉民國
http://www.dotblogs.com.tw/chou/archive/2009/06/21/8925.aspx
31. StreamReader 讀取時,中文字部分變成亂碼的解決方法。
使用 StreamReader 時,可指定字元編碼方式
StreamReader 建構函式 (Stream, Encoding) : 使用指定的字元編碼方式,針對指定的資料流初始化 StreamReader 類別的新執行個體。
因此只要指定編碼方式即可解決
程式碼
// 不指定 Encoding,其 Encodeing 為 Unicode
System.IO.StreamReader srNoEncode = new System.IO.StreamReader("DataFile.txt");
txtNoEncode.Text = srNoEncode.ReadToEnd();
// 指定 Encoding 為 System.Text.Encoding.Default (作業系統目前 ANSI 字碼頁的編碼方式)
System.IO.StreamReader srDefault = new System.IO.StreamReader("DataFile.txt",System.Text.Encoding.Default);
txtsrDefault.Text = srDefault.ReadToEnd();
執行結果
進階閱讀
System.Text.Encoding 類別
http://msdn.microsoft.com/zh-tw/library/system.text.encoding
使用 Bitmap.Clone 方法 (Rectangle, PixelFormat) : 建立藉由 Rectangle 結構和使用指定 PixelFormat 列舉型別定義的 Bitmap 之區段複本。
程式碼
// 原始影像,顯示於pictureBox1
Bitmap bmpOrg = new Bitmap("pic.jpg");
this.pictureBox1.Image = bmpOrg;
// 擷取部份影像,顯示於pictureBox2,區域為(起點x座標20, 起點y座標20, 寬度50, 高度50)
Bitmap bmpClone = bmpOrg.Clone(new Rectangle(20, 20, 50, 50), bmpOrg.PixelFormat);
this.pictureBox2.Image = bmpClone;
執行結果
33. String 轉為 Byte 序列與 Byte 序列轉為 String。
使用 System.Text.Encoding 類別中的這兩個方法,須注意編碼方式 :
Encoding.GetBytes 方法 : 將字元集編碼成位元組序列。
Encoding.GetString 方法 : 將位元組序列解碼成字串。
程式碼
String strOrg = "12345";
// Encoding.GetBytes方法,將 String 轉為 Byte 序列
byte[] stringConvByte = Encoding.Default.GetBytes(strOrg);
// Encoding.GetString方法,將 Byte 序列 轉為 String
string byteConvStrig = Encoding.Default.GetString(stringConvByte);
執行結果
34. 更改 SplitContainer 面板的配置為水平或垂直方向。
使用 SplitContainer.Orientation 屬性 : 取得或設定值,表示 SplitContainer 面板的水平或垂直方向。
SplitContainer.Orientation = = System.Windows.Forms.Orientation.Horizontal; // 垂直
SplitContainer.Orientation = System.Windows.Forms.Orientation.Vertical; // 水平,預設的配置
或者參考下圖做設定
使用 Convert.ToInt16 方法 (String, Int32) : 將指定基底中數字的 String 表示,轉換為相等的 16 位元帶正負號的整數。
其中
String value : 含有數字的 String。
Int32 value : String value 中數字的基底,必須是 2、8、10 或 16,也就是2進制、8進制、10進制、16進制。
*註 : 以下程式碼修改 &(AND) 為 |(OR),就可做 OR 運算。
程式碼
string s1 = "10000000";
string s2 = "10000001";
int i1 = Convert.ToInt16(s1, 2);
int i2 = Convert.ToInt16(s2, 2);
string sr = Convert.ToString(i1 & i2, 2);
MessageBox.Show(String.Format("{0} AND {1} = {2}",s1,s2,sr));
執行結果
參考
使用 DateTime.ToString 方法 (IFormatProvider) : 使用指定的特定文化特性的格式資訊,將這個執行個體的值轉換為它的對等字串表示。
以下舉兩個簡單例子
*註 : MM : 月份,mm : 分鐘,HH : 24小時制小時,hh : 12小時制的小時
程式碼
MessageBox.Show(DateTime.Now.ToString("yyyy/MM/dd"));// 日期 ex. 2009/02/04
MessageBox.Show(DateTime.Now.ToString("HH:mm:ss")); // 時間 ex. 17:10:10
37. 加入控制項到 Form、FlowLayoutPanel、GroupBox、Panel 中。
主要的方法為
(1) Controls.Add
(2) Control.Parent 屬性 : 取得或設定控制項的父容器。
程式碼
#region 使用 Controls.Add
private void button1_Click(object sender, EventArgs e)
{
// 加入 TextBox 到 Form
TextBox tb1 = new TextBox();
tb1.Name = "tb1";
tb1.Location = new Point(10, 10);
this.Controls.Add(tb1);
// 加入 TextBox 到 FlowLayoutPanel
TextBox tb2 = new TextBox();
tb2.Name = "tb2";
tb2.Location = new Point(10, 10);
this.flowLayoutPanel1.Controls.Add(tb2);
// 加入 TextBox 到 GroupBox
TextBox tb3 = new TextBox();
tb3.Name = "tb3";
tb3.Location = new Point(10, 10);
this.groupBox1.Controls.Add(tb3);
// 加入 TextBox 到 Panel
TextBox tb4 = new TextBox();
tb4.Name = "tb4";
tb4.Location = new Point(10, 10);
this.panel1.Controls.Add(tb4);
}
#endregion
#region 使用 Control.Parent 屬性
private void button2_Click(object sender, EventArgs e)
{
// 加入 TextBox 到 Form
TextBox tb1 = new TextBox();
tb1.Name = "tb1";
tb1.Location = new Point(10, 10);
tb1.Parent = this;
// 加入 TextBox 到 FlowLayoutPanel
TextBox tb2 = new TextBox();
tb2.Name = "tb2";
tb2.Location = new Point(10, 10);
tb2.Parent = this.flowLayoutPanel1;
// 加入 TextBox 到 GroupBox
TextBox tb3 = new TextBox();
tb3.Name = "tb3";
tb3.Location = new Point(10, 10);
tb3.Parent = this.groupBox1;
// 加入 TextBox 到 Panel
TextBox tb4 = new TextBox();
tb4.Name = "tb4";
tb4.Location = new Point(10, 10);
tb4.Parent = this.panel1;
}
#endregion
執行結果
(1) Controls.Add
(2) Control.Parent 屬性
38. 善用 SqlException,讓資料庫錯誤訊息更明確。
對資料庫操作產生的例外情況,可使用 SqlException
SqlException 類別 : 當 SQL Server 傳回警告或錯誤時所擲回的例外狀況。
以下顯示 SqlException 與 Exception 對於資料庫例外狀況所顯示的錯誤訊息。
*註 : 可以同時使用 SqlException 與 Exception,需注意順序是先 SqlException。
程式碼
private void Form1_Load(object sender, EventArgs e)
{
ShowSqlException("Data Source=127.0.0.1;Initial Catalog=ErrorDBName;User Id=ErrorID;Password=ErrorPWD;");
}
public static void ShowSqlException(string connectionString)
{
string queryString = "EXECUTE NonExistantStoredProcedure";
StringBuilder errorMessages = new StringBuilder();
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
try
{
command.Connection.Open();
command.ExecuteNonQuery();
}
//catch (SqlException ex) // 使用 SqlException
//{
// for (int i = 0; i < ex.Errors.Count; i++)
// {
// errorMessages.Append("Index #" + i + "\n" +
// "Message: " + ex.Errors[i].Message + "\n" +
// "LineNumber: " + ex.Errors[i].LineNumber + "\n" +
// "Source: " + ex.Errors[i].Source + "\n" +
// "Procedure: " + ex.Errors[i].Procedure + "\n");
// }
// MessageBox.Show(errorMessages.ToString());
//}
catch (Exception ex) // 使用 Exception
{
MessageBox.Show(ex.ToString());
}
}
}
執行結果
(1) 使用 Exception
(2) 使用 SqlException
39. 出現錯誤 [ 不會傳回任何重要資料行資訊的 SelectCommand 不支援 UpdateCommand 動態 SQL 的產生 ] 解決方式。
資料表需設定 Primary Key,如果使用 SELECT 指令中沒有回傳 Primary Key 的欄位,就無法由 CommandBuilder 產生 Insert/Update/Delete 的指令。
新增不需要主索引鍵,所以很多人就容易誤會資料庫或程式已就緒。
參考
http://social.msdn.microsoft.com/Forums/zh-TW/232/thread/79dd33cd-256c-4414-bbb8-26c7c3d5ac44
40. 程式中使用到 unsafe,出現 [ 程式中若有 unsafe 程式碼,編譯時必須使用 /unsafe 選項 ] 解決方式。
在方案按滑鼠右鍵 -> [ 屬性 ] -> [ 建置 ] 中,項目 [ 容許 Unsafe 程式碼 ] 打勾。
41. 出現錯誤 [ 找不到型別或命名空間名稱 'ManagementObject' ] 解決方式。
想要使用 WMI 功能,除了
using System.Management; // System.Management 命名空間
記得將 System.Management.dll 加入參考,請參考下圖
42. 在沒有 Visual Studio 的電腦環境下,如何註冊 DLL。
在沒有安裝 Visual Stduio 的電腦環境下,就沒辦法使用 Regasm 組件登錄工具,此時可將 RegAsm.exe 和 RegAsm.exe.config 複製到安裝包中,在安裝階段調用 RegAsm 來註冊 DLL。