2009-02-23

C# – Recursion & XmlTextWriter

image

最近因為程式的需要,必須提供一個功能給使用者 就是能讓他們自己建立TreeNode 這個部分相當簡單。。 只要去指定每個TreeNode的ContextMenuStrip屬性

   1:  TreeNode tnAdd = new TreeNode(NodeName);
   2:  tnAdd.ContextMenuStrip = contextMenuStrip1;

只是使用者還需要一個功能 就是能將所建立的Tree整個備份下來 當然,我直覺想到的是XML格式 因為除了要儲存每個Node名稱外 也需要儲存相關Node的資訊(像是Folder資訊、Document資訊) 在這裡我使用兩個主要的方式
1.Recursion(遞迴)
2.XmlTextWriter物件
使用Recursion是因為我並不清楚 底下會長出多少個Node,也就是我不清楚要用多少個迴圈 來找出所有的Node,利用Recursion 可以讓我不需要知道,也可以一層一層找下去 在寫Xml檔案時,我使用XmlTextWriter物件

   1:  string strFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 
   2:  strFolder=string.Format(@"{0}\{1}",strFolder,"DDA.xml"); 
   3:  //---Xml write---- 
   4:  using (XmlTextWriter xtw = new XmlTextWriter(strFolder, Encoding.UTF8)) 
   5:  { 
   6:    xtw.Formatting = Formatting.Indented;
   7:    xtw.WriteStartDocument();
   8:    xtw.WriteStartElement("List"); 
   9:    WriteElement(xtw, tvList.Nodes); 
  10:    xtw.WriteEndDocument(); 
  11:  }
  12:   
  13:  //---Recursion---- 
  14:  private void WriteElement(XmlTextWriter xtwThis, TreeNodeCollection tnCurrentNodes) 
  15:  { 
  16:    foreach (TreeNode thisNode in tnCurrentNodes) 
  17:    { 
  18:      xtwThis.WriteStartElement(thisNode.Text); 
  19:      if (thisNode.Nodes.Count>0) 
  20:      { 
  21:          WriteElement(xtwThis, thisNode.Nodes); 
  22:      } 
  23:    xtwThis.WriteEndElement();
  24:    } 
  25:  } 
  26:   

簡單寫下這些紀錄,可以供以後做參考用 在寫這支程式時,遇到一個小問題 就是我嘗試要在XML的主目錄下,建立多個Element 這會產生錯誤,在主目錄中只能增加一個Element 不曉得是不是這樣,先記錄下來。

參考資料
1.
http://chrisbalboa.wordpress.com/2007/10/02/aspnetxmltextwriter-demo-%E7%AF%84%E4%BE%8B/
2.
http://www.builder.com.cn/2007/0924/521705.shtml
3.
http://www.cnblogs.com/chen79/archive/2008/01/05/1027064.html

2009-02-18

Linq 基本語法 - Join

Join
The Join operator performs an inner equijoin on two sequences based on keys extracted from each element in the sequences.

public static IEnumerable<V> Join<T, U, K, V>(
this IEnumerable<T> outer,
IEnumerable<U> inner,
Func<T, K> outerKeySelector,
Func<U, K> innerKeySelector,
Func<T, U, V> resultSelector);


在這裡建立了兩個List
List ltUser = new List(20);
for (int i = 0; i < 20; i++)
{
  ltUser.Add(new User(i,"AA"));                
}
 
List ltUserInfo = new List(10);
for (int i = 0; i < 10; i++)
{
  ltUserInfo.Add(new UserInfo(i,"CC"));                
}

Linq語法如下:
var Users=ltUser.Join(ltUserInfo,
  a=>a.No,
  b=>b.No,
  (a,b)=>new{id=a.No,UserName=a.Name,Department=b.Department});
 
StringBuilder sb=new StringBuilder();
foreach (var item in Users)
{
  sb.AppendLine(item.ToString());                           
}
richTextBox1.Text=sb.ToString();

最後產生如下結果
image

最後產生的結果,有點像是Inner Join
其實最近有點懶散,並沒有很仔細去看這本書
今天就先練習到這。

Linq 基本語法 – Reverse

其實這一系列Linq基本語法
都有點像是在走馬看花,就大概看過有個印象
現在專案也並未運用到,就看看之後是否會使用這項技術
 

Reverse:
The reverse operator outputs a sequence of the same type as the input sequence but in the reverse order.

IEnumerable items = presidents.Reverse();
StringBuilder sb = new StringBuilder();
 
foreach (var item in items)
{
  sb.AppendLine(item);
}
 
richTextBox1.Text = sb.ToString();

最後得到如下結果:
image
其實Reverse就如解釋中所說的,只是反轉資料。

2009-02-17

Linq 基本語法 – OrderBy 與 OrderByDescending

這兩個使用方式都相當簡單

OrderBy:
The OrderBy operator allows an input sequence to be ordered based on a keySelector method that will return a key value for each input element, and an ordered output sequence, IOrderedEnumerable<T>, will be yielded in ascending order based on the values of the returned keys.

若繼續範例中的那個字串陣列

var nameObjs = presidents.OrderBy(s=>s);
StringBuilder sb = new StringBuilder();
 
foreach (var item in nameObjs)
{
  sb.AppendLine(item);                
}
richTextBox1.Text = sb.ToString();


可以得到如下結果:
 
image

OrderByDescending:
This operator is prototyped and behaves just like the OrderBy operator, except that it orders in descending order.

從上面的字義,可以很清楚了解到
其實OrderByDescending是降冪排序
而OrderBy是升冪排序

var nameObjs = presidents.OrderByDescending(s=>s);
StringBuilder sb = new StringBuilder();
 
foreach (var item in nameObjs)
{
  sb.AppendLine(item);                
}
 
richTextBox1.Text = sb.ToString();


最後產生如下結果:   
image

2009-02-12

Linq 基本語法 - Take

在開始寫這篇練習前,心裡有點感觸先寫下來
昨天正在網頁上搜尋Linq的資料時
看到DAVID DONG大大的網誌
http://studyhost.blogspot.com/2009/02/silverlight.html

他在文中提到-為了爭取到某一個案子,在時程評估的時候,就已經放棄架構了,我們給了客戶一個若要遵循架構就根本不可能達成的預計完成時間。

這樣的情況,在我開發的這短短不到兩年裡
也碰到了幾次。我是最底層的開發人員
也不是資工背景出身的人,做的也並不是SA的工作
(說穿了只是[程式勞工]或稱為[程式開發機])
而做的程式,往往送交給業主後
都面臨到到[程式大改]的情況
當我偶然的機會,聽到MVC架構時
我ㄧ直Push自己,能多遵循這樣的架構開發程式

MVC的好處,我不再多說明
要開發MVC必須要做點苦功,才能發揮它真正的效用
一開始的設計階段是滿痛苦的,你必須要捨棄一些方便性
有時也很想直接放棄這樣的架構,但我總認為時間是寶貴的
程式開發後的維護更是重要
並不希望程式開發出去後,再丟回來維護時
又因為需求變更,而讓程式又大改。

恩~廢話少說,繼續Linq學習紀錄。

---------------------------------------------------------------------
上一篇提到的那本書中
對於Take語法,有以下註解
The Take operator returns a specified number of elements from the input sequence
簡單來說Take就是選取前面幾個

IEnumerable items = presidents.Take(5);

像上面的例子,就是選取前面五個Element。

至於TakeWhile語法
The TakeWhile operator yields elements from an input sequence while some condition is true.
簡單來說,就是符合條件為True時則選擇
不符合條件即跳出。
IEnumerable items = presidents.TakeWhile(s => s.Length < 10);

像上面的例子來說,當長度大於10則"不再"去選擇

2009-02-11

Linq 基本語法-Select

在看Apress.Pro LINQ(作者Joseph C. Rattz,Jr.)這本書時
看到這段範例(稍微改寫過)
Example1
首先定義一個字串陣列presidents

string[] presidents = {"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",    
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",    
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",    
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",    
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",    
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};

Select語法:
var nameObjs = presidents.Select((p,i) => new { Index=i, Name=p });
StringBuilder sb = new StringBuilder();
 
foreach (var item in nameObjs)
{
  string name = string.Format(@"{0}. {1}",item.Index+1,item.Name);
  sb.AppendLine(name);
}
 
richTextBox1.Text = sb.ToString();

最後產生的結果如下
image

Example2(SelectMany用法)

Employee[] employees = Employee.GetEmployeesArray();
EmployeeOptionEntry[] empOptions = EmployeeOptionEntry.GetEmployeeOptionEntries();
 
var employeeOptions = employees
.SelectMany(e => empOptions
.Where(eo => eo.id == e.id)
.Select(eo => new {
id = eo.id,
optionsCount = eo.optionsCount }));
 
foreach (var item in employeeOptions)
  Console.WriteLine(item);


其實看完這個範例,我還是依舊不懂
所以上網查了一下,看到這兩篇文章
http://www.tzwhx.com/newOperate/html/1/11/112/14415.html
http://www.cnblogs.com/aspnet2008/archive/2008/12/19/1357690.html
大概看了一下,好像是因為Linq語法並沒有SQL的Join
才會有SelectMany這個方法,我不確定先記錄下來!

2009-02-10

LINQ初體驗

最近聽到這個名詞LINQ(Language-Integrated Query)
簡單來說:會有這項技術產生,
也是因為現階段查詢語法過於繁雜。

就拿要處理簡單的XML資料來說,
處理資料的方式就有 XPath、XmlDocument物件、XQuery,
或是使用XSLT的方式 就連不同的資料庫,
雖然都是使用SQL語法 但各家廠商都不盡相同。

在這篇文章中提到
http://www.ithome.com.tw/itadm/article.php?c=44337 簡化大量的細節運作:將「如何(How)取得資料」,換成「要操作什麼(What)資料」:這意味著LINQ將存取最佳化交由專家來做,如:由DB引擎來最佳化存取資料。

其實這句話就已經說明了很詳細。 Linq好用的地方,我在此就不在詳述 畢竟依照我小嫩嫩程式的功力 不敢在高手面前耍大刀 我只想紀錄一下第一次使用的心得

首先先定義一個int 陣列

//--自訂一個Int陣列
int[] intArray=new int[]{2,4,5,6,4,2,7,8,8};
StringBuilder sb = new StringBuilder();
 
foreach (int intItem in intArray)
{
   if (intItem>5)
      sb.AppendLine(intItem.ToString());    
}
 
richTextBox1.Text = sb.ToString();



接下來則使用Linq語法查詢

////--利用Linq語法 Where找尋大於5 
 
IEnumerable selectItem = intArray.Where(i => i > 5);
StringBuilder sb = new StringBuilder(selectItem.Count());
 
foreach (int thisInt in selectItem)
{ 
  sb.AppendLine(thisInt.ToString());
}
richTextBox1.Text = sb.ToString();


其實這篇只是簡單的紀錄一下小小心得,
還有很多關於Linq的功能,還得繼續研究下去。

2009-02-08

DataTable - 每個Cell可以存放物件

這次在撰寫需求程式時,遇到一個狀況
就是我希望在UI的DataGridView控制項上
顯示我自訂的Table資料
可是這個Table中,我也希望能同時將其餘的資訊也保留進來
只是顯示的時候只顯示我要的欄位

這樣說好像有點模糊,譬如以下圖示
image
我希望的是當我顯示Document Name的時候
也同時將Document的所有相關資訊,存進這個自訂的Table
(每一個DataRow代表不同的Document資訊)
以方便讓我的程式去做資料的讀取
(DataGridView顯示方式,是去指定DataGridView.DataSource屬性)

其實,每個DataRow的Cell可以存放物件
不單單只可以存放字串
只是要注意的是,若要在DataGridView上顯示
必須要overrride ToString()這個Method

再這裡我自訂一個QVFDocInfo Class,然後override ToString()

這樣就可以在我指定DataSource時,只秀出我要的字串
也同時將我的自訂物件存進DataTable裡。

public class QVFDocInfo
{
  private string docName;
  
  public string DocName
  {
    get { return docName.Replace("_",""); }            
  }
 
  private string obid;
 
  public string Obid
  {
    get { return obid; }
  }
 
  private string latestorAll;
 
  public string LatestorAll
  {
    set { latestorAll = value; 
  }
  
  get { return latestorAll; }            
  }
 
 
  #region Constructor
  public QVFDocInfo(string docName, string obid)
  {
    this.docName = docName;
    this.obid = obid;
  }
 
  public QVFDocInfo(string docName, string obid,string LatestorAll)
  {
    this.docName = docName;
    this.obid = obid;
    this.latestorAll = LatestorAll;
  }
  #endregion        
 
  public override string ToString()
  {  
    return docName.Replace("_","");
  }
}

2009-02-02

if 判斷簡化寫法

private bool GetResult(object o)
 
{
 
    if (o==null)
 
 
    {
    
    return false;                
    }
    else
    {
    
    return true;
    }        
 
}
假設今天有這樣一個判斷Method
單純只是要判斷傳入的參數是否為Null
然後回傳一個bool值(true or false)
一般的寫法都應該會是上面那樣




其實可以簡化成以下寫法
private bool GetResult(object o)
 
{
 
    return o == null;            
 
}

程式碼是不是更簡單明瞭多了呢??


2009-02-01

Enum的小技巧

曾在瓶水相逢.Net的Blog中看到這篇文章
Enum 的設計與應用 - 簡易權限設計
當時看到這篇就對這篇印象很深
第一次看到Enum也可以這樣使用

今天一早,原本正看著Essential C# 3.0這本書時
又突然看到[FlagsAttribute]
上網查一下MSDN,又讓我想起那篇文章
因為之前時間不夠,並未實際測試
趁今天比較空閒時,寫了一個小程式來測試一下

[FlagsAttribute]
private enum UserPriority
{
  None = 0,
  Read = 1,
  Write = 2,
  Delete = 4
};
private void button1_Click(object sender, EventArgs e)
{
  richTextBox1.Text = string.Empty;
  StringBuilder sb = new StringBuilder();
 
  for (int i = 0; i < 8; i++)
  {
    sb.AppendFormat(@"UserPriority{0}: {1}",i, ((UserPriority)i).ToString());
    sb.AppendLine();                
  }
  richTextBox1.Text = sb.ToString();
}

測試結果如下所示:
 image
果然,印證了MSDN上的結果
Enum也可以使用AND、OR、XOR的運算
雖然有點多此一舉
(MSDN上已經詳細說明了,但還是想實際測試看看加深印象)