2009年6月25日 星期四

發神經的 VS.NET 2008

平常用 3.0 以後提供的語法 & 功能習慣了.....例如:
public string test { get; set; }

var myVar = "text";

var newObject = new MyObject { Name = "myobject", Age = 12; }
大概就以上這些語法.......

今天用 VS.NET 2008 開啟後,重新編譯卻發現這些語法都死光光了.....例如出現以下訊息:
'xxxxxxx' 不是標記成 abstract 或 extern,因此必須宣告主體
上面就是因為用了第一段程式碼的第一行語法所出現的錯誤.....(但這是 2.0 才會出現的...)

看到這情況真是莫名其妙,於是再專案"屬性頁"中,在"建置"中的目標 Framework 中選擇 ".NET Framework 3.0" 編譯一次(當然會錯誤),再改回 ".NET Framework 3.5" 編譯一次就正常了....

2009年6月23日 星期二

[WPF] 項目控制項

簡介

由於項目控制項繼承自 System.Windows.Controls.ItemsControl 類別,因此可以容納整個集合的物件,不限定單一物件,而且每個項目都可以是任何物件。(UIElement 會呈現出來,非 UIElement 則是顯示 ToString() 的結果)

ItemsControl 有幾個屬性必須要了解:
  1. HasItems:用來檢查集合中有沒有內容

  2. IsGrouping:用來辨識集合中的項目是否有分群

  3. DisplayMemberPath:使用項目物件中的屬性來顯示(也可以是運算式喔!)

而項目控制項大致可分為以下三類:
  1. 選取器

  2. 功能表

  3. 其他項目控制項



選取器

選取器的特色在於可用 index 的方式存取,並且可以選取。

因此選取器繼承 ItemsControl 之後,額外加入了處理選取功能的屬性,例如 SelectedIndex、SelectedItem、SelectedValue .... 等等都是。

而 WPF 中提供了四個選取器控制項,分別是 ComboBoxListBox、ListView、TabControl。


ComboBox

ComboBox 中定義了屬性 IsDropDown 可判斷目前下拉式選單的狀態是展開或是收合;另外還定義了兩個事件,分別是 OnDropDownOpened 以及 OnDropDownClosed,可在有特殊需求時填入相對應的程式碼。

以下為範例:
(IsEditable = false)

(IsEditable = true)

若是要更清晰的表達每個項目,可使用 ComBoxItem 標籤包住每一個項目內容,如此一來,不只清楚,還可以在 ComboBoxItem 標籤上加上 IsSelected 或是 IsHightlighted 等屬性。

但若使用 ComboBoxItem,TextSearch.Text 屬性就無法設定在上面範例的 StackPanel 上,而是要設定在 ComboBoxItem 上囉!


ListBox

基本上 ListBox 跟 ComboBox 是很相似的,只是 ListBox 一次顯示所有項目而已,且有三種不同的選取模式:
  1. Single (預設)

  2. Multiple

  3. Extended:搭配 Shift/Ctrl 進行多選

而 ComboBox 有 ComboBoxItem 標籤,ListBox 也有 ListBoxItem 標籤可以使用囉!


ListView

ListView 繼承自 ListBox,額外增加了 View 的屬性,可以讓開發者自訂更豐富的顯示方式,以下示範使用方式:




TabControl

TabControl 是很基本的控制項,以下為示範:





功能表

這部分有 Menu 以及 ContextMenu 兩個控制項,使用起來的效果與原本 2.0 中其實是差不多的,可以參考以下範例:




其他項目控制項

此部分包含了 TreeView、ToolBar、StatusBar 等等。

TreeView

以下是 TreeView 控制項的使用範例:

另外還有查到 TreeView 的使用範例教學,可以參考看看!

而 TreeViewItem 較為常用的屬性有 IsExpanded、IsSelected 兩個屬性,以及 Expanded、Collapsed、Selected、Unselected 這幾個事件囉!


ToolBar

可以把 ToolBar 想像是功能表的加強版! 可以將許多按鈕群組在一起。

以下找到一個簡單的使用範例教學:



StatusBar

StatusBar 也像是功能表,但其項目是以水平堆疊而成的,上網找到幾個不錯的相關教學:


2009年6月19日 星期五

[WPF] 內容控制項

簡介

內容控制項的 Content 僅能放入一個物件,皆繼承自 System.Windows.Controls.ContentControl 類別,而 Content 中的物件可以是任何型別,放入的 element tree 有多大皆可! 但僅能有一個直接的 child element。

ContentControl 中有個 HasContent 屬性,有此屬性的定義,就可以透過屬性觸發程序很輕易的在 HasContent 屬性改變時進行其他屬性的設定動作。
(上面這一招在 WPF 中使用很多.............)

內容控制項分為三大類:
  1. 按鈕

  2. 簡單容器

  3. 有標題的容器



按鈕

在 WPF 中,按鈕繼承自 System.Windows.Controls.Primitives.ButtonBase 類別,其中以下幾個控制項都繼承自 ButtonBase:
  1. Button

  2. RepeatButton

  3. ToggleButton

  4. CheckBox

  5. RadioButton
 

Button

WPF 中的 Button 類別只有在 ButtonBase 上增加了「取消按鈕」以及「預設按鈕」兩個機制,這兩個機制在對話方塊中很有用:
  1. 當 Button.IsCancel = true,此按鈕屬於取消按鈕,點選之後會關閉按鈕所屬的視窗並設定 DialogResult = false。

  2. 當 Button.IsDefault = true,此按扭屬於預設按鈕,當按鈕取得焦點時,按下 Enter 就等於按下此按鈕。


RepeatButton

RepeatButton 按著不放會持續觸發 Click 事件,但由於直接繼承 ButtonBase 類別,因此沒有取消以及預設兩種機制存在。

而 RepeatButton 持續觸發 Click 事件的頻率取決於 Delay 以及 Interval 兩個屬性,預設即為 SystemParameters.KeyboardDelay 以及 SystemParameters.KeyboardSpeed

看到以上描述有想起什麼嗎? 沒錯! 就是之前提過的 DependencyProperty(相依屬性) 啊~


ToggleButton

ToggleButton 可視為「會粘住」的按鈕,因此點選以後會保持狀態,第一次點選 IsChecked = true,再一次點選 IsChecked = false。

IsThreeState 屬性為 true,則 IsChecked 的值的變化為 true -> null -> false,對應到事件的觸發則是:
  • IsChecked = true 觸發 Checked 事件

  • IsChecked = false 觸發 Unchecked 事件

  • IsChecked = null 觸發 Indeterminate 事件


CheckBox

CheckBox 的特性相當類似於 ToggleButton,因此他是繼承自 ToggleButton 而來的,只是外觀有點不同罷了!


RadioButton

RadioButton 也是繼承自 ToggleButton,另外還支援了單選功能(同一群組內)。



簡單容器

Label

在 WPF 中的容器控制項,幾乎都可以擺入任意型態的物件,但唯讀 Label 僅能放入文字內容。

但雖然如此,Label 控制項卻可以搭配 Alt 進行快捷鍵的設定喔!

以下程式會在按下 Alt + U 時,焦點會自動跳到 TextBox 上:



ToolTip

ToolTip 是用來顯示提示訊息用,原本都是顯示文字訊息而已,但在 WPF 中,已經可以顯示任何的內容了! 以下有個簡單範例:



另外若是要讓 ToolTip 有更多不同的方式進行呈現時(例如:顯示時間長短),可搭配 ToolTipService 靜態類別來達成!


Frame

Frame 也可以放入任意內容,且可以同時支援 HTML & WPF,透過設定 Source 屬性就可以在 Frame 中顯示連結的內容。



有標題的容器

此部分介紹的控制項(GroupBox、Expander),由於繼承自 System.Windows.Controls.HeaderedContentControl 類別,因此多了一個型態為 Object 的 Header 屬性。而這代表什麼? 代表 Header 可以放進任何你想要放的東西.......


GroupBox

我們通常將 GroupBox 用將多個控制項歸納為相同群組時使用,但由於它是內容控制項,因此只能有一個 child element,因此我們要用其他的容器來當中介:




Expander

Expander 類似 GroupBox,但有個按鈕可以讓使用者開啟 & 收合所包含的內容:



此外,Expander 還定義了 IsExpanded 屬性以及 OnExpanded / OnCollapsed 兩個事件,還可以透過 ExpandDirection 來控制內容展開的方向。

2009年6月17日 星期三

[LINQ] 初探 LINQ to Objects

哪些類別支援 LINQ 相關功能 ?

LINQ to Objects 表示要透過 LINQ 與集合型態的物件進行互動,這些資料存在於 memory 中,但是 .NET Framework 提供的類別如此之多,支援 LINQ 存取的是哪些呢?

答案就是有實作 System.Collections.IEnumerable 介面的類別所產生的物件都可以

何以見得? 由於 .NET Framework 3.0 以後加入了 Extension Method(擴充方法) 這個機制,且又在 System.Linq.Enumerable 類別中針對實作 System.Collections.IEnumerable 介面的類別加入了許多 Extension Method,而這些類別(Array、List、Dictionary .... 等等)則可說是「自動擴充」成擁有 LINQ 的相關功能。



使用範例

首先是 LINQ to Object Array:

using System;
using System.Linq;

class Program
{
static void Main(string[] args)
{
//定義各種不同型態的資料
Object[] array = { "String", 12, true, 'a' };

var types = array.Select(item => item.GetType().Name) //選取集合中資料的型態
.OrderBy(type => type); //根據型態進行排序

/* 執行結果:
Boolean
Char
Int32
String */
ObjectDumper.Write(types);
Console.ReadLine();
}
}



接著是 LINQ to 自行定義的物件(Book) Array:

using System;
using System.Linq;
using LinqInAction.LinqBooks.Common;

class Program
{
static void Main(string[] args)
{
Book[] books = { new Book { Title = "LINQ In Action" },
new Book { Title = "LINQ For Fun" },
new Book { Title = "Extreme LINQ" } };

var titles = books.Where(book => book.Title.Contains("Action")) //取得 Title 欄位包含 "Action" 關鍵字的書籍資料
.Select(book => book.Title); //取得 Title 欄位

/* 執行結果:
LINQ In Action */
ObjectDumper.Write(titles);
Console.ReadLine();
}
}



其實,只要是 Array,存放於 Array 中可以是任何型態的物件(因為 Array 有實作 System.Collections.IEnumerable 介面)


接著改用 List,除了型態不同以外,query 的方法可說是完全相同:

using System;
using System.Collections.Generic;
using System.Linq;
using LinqInAction.LinqBooks.Common;

class Program
{
static void Main(string[] args)
{
//即使資料換成是 List,LINQ 的語法也是相同的!
List books = new List() { new Book { Title = "LINQ In Action" },
new Book { Title = "LINQ For Fun" },
new Book { Title = "Extreme LINQ" } };

var titles = books.Where(book => book.Title.Contains("Action")) //取得 Title 欄位包含 "Action" 關鍵字的書籍資料
.Select(book => book.Title); //取得 Title 欄位

/* 執行結果:
LINQ In Action */
ObjectDumper.Write(titles);
Console.ReadLine();
}
}



這就是 LINQ 想要達成的目標 => 讓 query 的語言一致!
目前嘗試 Array 與 List 的確有這種感覺~


最後是 LINQ to Dictionary,並用兩種不同的方式(query operator & query expression)進行查詢:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main(string[] args)
{
Dictionary myNumbers = new Dictionary();
myNumbers.Add(0, "zero");
myNumbers.Add(1, "One");
myNumbers.Add(2, "Two");
myNumbers.Add(3, "Three");
myNumbers.Add(4, "Four");

//透過 query operator 的方式取得偶數值
var evenNumbers01 = myNumbers.Where(number => number.Key % 2 == 0)
.Select(number => number.Value);
ObjectDumper.Write(evenNumbers01);

//也可以透過 query expression 的方式取得偶數值
var evenNumbers02 = from number in myNumbers
where (number.Key % 2) == 0
select number.Value;
ObjectDumper.Write(evenNumbers02);

/*
以上兩個執行結果都會是:
Zero
Two
Four
*/
Console.ReadLine();
}
}


由此可見,由於 Extend Method 機制的出現,幾乎讓所有集合型態的資料都可以透過 LINQ 的方式進行存取了,只要有實作 System.Collections.IEnumerable 介面即可。

除此之外,查詢的方式也不僅限於一種,除了 query operator 外也還有 query expression 可以使用,甚至兩種同時搭配使用亦可喔!

[C#] Deferred Query Execution

什麼是 Deferred Query(延遲查詢) Execution 呢?

這是在看 LINQ In Action 的時候發現的,查詢了一下,原來這是 C# 2.0 就已經提供的功能.....

用途在於可以用更少的資源(Resource)使用集合(collection)物件!

為何這麼說呢? 以下用一段程式碼來說明:


using System;
using System.Linq;

namespace DeferredQueryExecution
{
class Program
{
static double Square(double n)
{
//每呼叫 Square 就會印出下列訊息
Console.WriteLine("Computing Square(" + n + ")....");
return Math.Pow(n, 2);
}

static void Main(string[] args)
{
int[] numbers = { 1, 2, 3 };

//取得 numbers 陣列中所有元素的平方值並存入 query 集合物件中
var query =
from n in numbers
select Square(n);

//印出 query 集合物件的內容
foreach (var n in query)
Console.WriteLine(n);

Console.ReadLine();
}
}
}



這一段程式碼執行完的結果會是如何呢? 一般來說,應該是以下這樣....
Computing Square(1)....
Computing Square(2)....
Computing Square(3)....
1
4
9

但實際跑出來的結果並非這樣,而是:
Computing Square(1)....
1
Computing Square(2)....
4
Computing Square(3)....
9

結果令人出乎意料吧!

從結果可以看出,.NET compile 在處理集合物件時,並非一次給定完整結果,而是「真的有需要才一個一個慢慢給出」,因此當集合物件的數量龐大時,可以有效降低系統資源的浪費,提升在操作集合物件時的效能。

當然,這跟 LINQ 好像沒啥關係......因此只要了解一下 .NET 有這種機制存在即可囉!

2009年6月12日 星期五

[C#] delegate(委派) -> Lambda Expression -> LINQ

觀念解說

關於 delegate & Lambda Expression & LINQ 入門,參考以下文章可以得到很清楚的觀念喔!

Huan-Lin 學習筆記: C# 筆記:重訪委派-從 C# 1.0 到 2.0 到 3.0

Huan-Lin 學習筆記: C# 筆記:從 Lambda 表示式到 LINQ

C# 3.0 極簡風 - Lambda Expression - 黑暗執行緒


接著以下只記錄一些瑣碎的筆記........


LINQ 從何而來?

Lambada Expression 大量了使用了之前所提到的 extension method,而 .NET 中也提供了不少的 extension method 以提昇 Lambada Expression 的易用性,藉此讓 LINQ 的語法更加的直覺!

舉例來說,在 System.Linq.Enumerable class 中,就定義了許多 extension method,例如:OrderByDescendingLastMaxMinContainsCount.... 等等。


除了 delegate & Lambda Expression 之外,與 LINQ 有關的特殊功能還有 Implicit typed local variables、Object and collection initializers、Anonymous types 等等。

而除了 delegate 之外,都是在 C# 3.0 中才有提供的(當然 VB.NET 也有),因此看得出來,LINQ 可說是集合所有新功能於一身的查詢技術。


範例說明

以上範例將上述的新功能簡單做了一次完整的結合測試:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace CompleteCode
{
//為了將 Extension Method 定義在此類別, 要加上 static 關鍵字
//否則就要另外定義一個 static class 來放 Extension Method
static class Program
{
static void Main(string[] args)
{
//在呼叫時指定比對用的 function (使用 Lambda Expression)
DisplayProcesses(process => process.WorkingSet64 >= 20 * 1024 * 1024);

Console.ReadLine();
}

//定義 inner class
class ProcessData
{
public Int32 Id { get; set; }
public Int64 Memory { get; set; }
public string Name { get; set; }
}

//此處以委派(delegate)的方式將 match 函式交由呼叫端決定
//傳入的參數型態為 System.Diagnostics.Process
//回傳型態為 Boolean
static void DisplayProcesses(Func match)
{
//此處變數型態會由 compiler 在編譯時決定
var processes = new List();

foreach (var process in Process.GetProcesses())
{
//使用 Object Initializer 的方式宣告物件並給定值
if (match(process))
processes.Add(new ProcessData { Id = process.Id, Name = process.ProcessName, Memory = process.WorkingSet64 });
}

Console.WriteLine("Total memory: {0} MB", processes.TotalMemory() / 1024 / 1024);

//透過 .NET 內建的 Extension Method,取得耗用記憶體最大的兩個 process 所耗費的記憶體總計
var top2Memory = processes.OrderByDescending(process => process.Memory)
.Take(2)
.Sum(process => process.Memory) / 1024 / 1024;
Console.WriteLine("Memory consumed by the two most processes: {0} MB", top2Memory);

//使用 Anonymous Type 宣告物件並顯示
var results = new { TotalMomery = processes.TotalMemory() / 1024 / 1024,
Top2Memory = top2Memory,
Processes = processes };
ObjectDumper.Write(results, 1);
}

//定義 Extension Method(計算記憶體總使用量)
//針對 IEnumerable 型別進行擴充
static Int64 TotalMemory(this IEnumerable processes)
{
Int64 result = 0;

foreach (var process in processes)
result += process.Memory;

return result;
}
}
}

2009年6月9日 星期二

[C#] 3.0 中的新功能 - 擴充方法(Extension Method)

簡介

擴充方法能將方法「加入」至現有型別,但不需要建立新的衍生型別 (Derived Type)、重新編譯,或是修改原始型別。

神奇的是,不僅是自訂的型別可以增加 extension method,連既有的型別都可以增加 extension method !

隨便舉個例,假設要檢查字串是否為數字,以前都是另外寫個 function 來檢查,例如:
public bool IsNumeric(string strVal);

現在若是透過 extension method,只要透過以下方式即可:
strVal.IsNumeric();

如何? 使用起來是不是更加直覺了呢?

[LINQ ] 初探

簡介

LINQ 是 Microsoft 開發出來專門用來處理集合資訊用的技術,什麼叫做集合資訊呢?

舉凡 Database、XML、Object、DataSet、Array、Collection .... 等都可以算是集合資訊

而我們再開發軟體時,資料來源也就差不多是上面這些,但每一種資料來源都有很多額外的知識必須要學..... Database 是一門學問、XML 又是一門學問 ...

想像一下若是可以用同一套語法來存取以上這些資料來源,不是很迷人的事情嗎?

而 LINQ 就是為了這個目的而產生的!

瞭解一下 LINQ 的目標就可以知道他有多酷了:(from LINQ In Action)
  1. Integrated objects, relational data, and XML (這當然是首要目的)

  2. SQL and XQuery-like power in C# and VB (整合進 C# & VB.NET 囉)

  3. Extensibility model for languages (提供其他語言的擴充性)

  4. Extensibility model for multiple data sources (當然也提供了不同資料來源的擴充性)

  5. Type safety (透過 compile-time 檢查)

  6. Extensive IntelliSense support (enabled by strong-typing) (這對開發者肯定是一大福音啊!)

  7. Debug support (這功能沒有怎麼可以呢?)



使用範例

首先來個使用範例,LINQ to Object !



using System;
using System.Linq;

namespace HelloLinq
{
class Program
{
static void Main(string[] args)
{
//string array
string[] words = { "hello", "wonderful", "linq", "beautiful", "world" };

//取得陣列中字串長度小於等於 5 的字串
var shortwords = from word in words
where word.Length <= 5
select word;
/* hello
linq
world */
foreach (var word in shortwords)
Console.WriteLine(word);


//依照字串長度分群組
var groups = from word in words
orderby word ascending
group word by word.Length into lengthGroups
orderby lengthGroups.Key descending
select new { Length = lengthGroups.Key, Words = lengthGroups };
/*
words of length 9
beautiful
wonderful
words of length 5
hello
world
words of length 4
linq
*/
foreach (var group in groups)
{
Console.WriteLine("words of length " + group.Length);
foreach (string word in group.Words)
Console.WriteLine(" " + word);
}

Console.ReadLine();
}
}
}




看到範例的第一個部分,也許有人會覺得沒有 LINQ 也是很好寫吧!

但第二部份,不是用 LINQ 的話,可就很費工囉!

然而,範例雖然簡單,還是可以看出 LINQ 的語法真的是相當直覺......加上 VS.NET 的 IntelliSense....(難怪 MS 的開發工具這麼多人用.....)


接著以下的範例,可以看出 LINQ 如何以幾乎無縫的方式整合進 C#(VB.NET 也行啦) 中,搭配 XML API 來產生 XML 文件:


using System;
using System.Linq;
using System.Xml.Linq;

namespace HelloLinqToXml
{
class Book
{
public string Publisher;
public string Title;
public int Year;

public Book(string title, string publisher, int year)
{
Title = title;
Publisher = publisher;
Year = year;
}
}

class Program
{
static void Main(string[] args)
{
//定義 object collection
Book[] books = new Book[] {
new Book("Ajax in Action", "Manning", 2005),
new Book("Windows Forms in Action", "Manning", 2006),
new Book("RSS and Atom in Action", "Manning", 2006)
};

//從 object collection 中取得資料後,並搭配 XML API 產生 XML 文件
XElement xml = new XElement("books",
from book in books
where book.Year == 2006
select new XElement("book",
new XAttribute("title", book.Title),
new XElement("publisher", book.Publisher)));

Console.WriteLine(xml);
Console.ReadLine();
}
}
}




最後一個部分則是 LINQ to SQL,此處以 NorthWind 為範例資料庫:


using System;
using System.Linq;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Data.SqlClient;

namespace HelloLinqToSql
{
class Program
{
static void Main(string[] args)
{
//設定資料來源
DataContext db = new DataContext(new SqlConnection("Server=CIC-GODLEON\\SQLEXPRESS;Database=northwind;Trusted_Connection=True;"));

//透過 LINQ 來取得資料
var contacts =
from contact in db.GetTable()
where contact.City == "Paris"
select contact;

foreach (var contact in contacts)
Console.WriteLine("Bonjour " + contact.Name);

Console.ReadLine();

}
}


///
/// 必須透過設定 attribute 的方式指定 class 和 DB table 的 mapping
/// 此處指定對應到 Customers 資料表
///

[Table(Name="Customers")]
class Contact
{
///
/// 同樣內部的設定也必須要透過 attribute 的方式設定 mapping
///


//未指定則對應到同名(CustomerID)欄位
[Column(IsPrimaryKey=true)]
public string CustomerID { get; set; }

//指定對應到 ContactName 欄位
[Column(Name="ContactName")]
public string Name { get; set; }

//對應 City 欄位
[Column]
public string City { get; set; }
}
}





參考資料

2009年6月2日 星期二

[SQL Server] Alias 的用法

今天被問到....

怎麼用 SQL Server Management Studio 去連 default port number 不是 1433 的 SQL Server..

直覺就是到 SQL Server Configuration Manager 去修改 default TCP/IP port number

可是後來想到.....其他設定不就沒辦法動了?

因此後來改用 Alias 來設定

Google 了一下找到這一篇「How to setup and use a SQL Server alias

很容易就完成設定囉!

[Oracle] 如何做到 MySQL 中的 LIMIT 效果

用過 MySQL 的人應該知道

若是要取得 Table A 的第 11~20 筆資料,只要透過 LIMIT 關鍵字就可以輕易取得!

但若是在 Oracle 中想要達成這種效果呢?

只要將 ROWNUM 以及 MINUS 搭配使用就可以囉!

以下有幾個參考連結:

新的開始: Oracle的Rownum的使用

丑角的天空: ORACLE : 列數限制查詢,SQL SELECT ROWNUM