2009年8月31日 星期一

在WPF的XAML裡面使用自訂的控制項

在WPF裡面自訂控制項很簡單
可以參考在WPF中新增自訂控制項
如果要使用的時候其實就直接宣告那個新增出的類別就好

public Window1()
{
InitializeComponent();

/// new a NewButton, and set it into window
NewButton b = new NewButton();
this.Content = b;
}

不過因為習慣上會希望將這些不變的介面元素宣告在XAML裡面
那就要先在XAML裡面先宣告namespace

<Window x:Class="test_wpf.Window1"
...
xmlns:test_wpf="clr-namespace:test_wpf"
...>
</Window>

xmlns:後面接的是在XAML裡面的命名空間(namespace),可以隨意取
後面clr-namespace:後面的則是在C#裡面原本使用的命名空間

之後需要加入該命名空間裡面定義的控制項時
就可以用"該命名空間:控制項"來取得

<Window x:Class="test_wpf.Window1"
...
xmlns:test_wpf="clr-namespace:test_wpf"
...>
<!--add custom user control here-->
<test_wpf:NewButton />
</Window>

在WPF中新增自訂控制項

要做自訂的控制項很簡單
比較重要的是希望做到什麼程度的自訂
在wpf裡面基本上有四類
繼承類別說明
現有元件僅須做簡單改動即可,但自訂空間較小
UserControl可輕易的做出複合控制項,自訂空間自由,推薦
Control自訂空間更大,但須自行定義的東西較多,適合想用ControlTemplate自訂控制項的外觀或製作支援不同的主題的控制項的使用者
FrameworkElement完全不以現有元件為基礎,適合想要精準控制外觀或屬性的使用者

第一種方法是最簡單的,如果你只是想要有多一個屬性的button或是想要先訂好一些預設的事件處理函式(event handler)的話,那就直接繼承該選項,然後複寫你想要改變的屬性或新建屬性進去就可以了

public class NewButton1 : Button
{
/// constructor to set default event handler
public NewButton1()
{
Click += new RoutedEventHandler(Click);
}

/// default event handler of click, switch color
void Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;

if (b.Background == Brushes.Red)
{
b.Background = Brushes.Green;
}
else
{
b.Background = Brushes.Red;
}
}
}

不過這個用法只適用於不需要做太多複雜變更的單一控制項
如果希望能夠有更多的自訂空間的話,那就繼承UserControl

public class NewButton2 : UserControl
{
/// constructor to set default event handler
public NewButton2()
{
Button b = new Button();
b.Click += new RoutedEventHandler(Click);
this.Content = b;
}

/// default event handler of click, switch color
void Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;

if (b.Background == Brushes.Red)
{
b.Background = Brushes.Green;
}
else
{
b.Background = Brushes.Red;
}
}
}

上面兩個NewButton基本上是相同的
不過繼承自UserControl的NewButton2只要把Content改成一個Grid裡面就可以很容易的再增加一些其他原有的元件,對於需要使用複合元件的使用者來說會更方便一點

同時,繼承自UserControl的方式,多了一種新增的方法
可以在方案總管(Solution Explorer)的專案上面按右鍵
直接選擇新增使用者控制項(User Control)

這樣還會同時新增出一個xaml檔案
可以將一些屬性的設定直接寫在xaml檔案裡面

<UserControl x:Class="test_wpf.NewButton2"
...
>
<Button Click="Click" />
</UserControl>

一般狀況下使用上面的方法是最方便也最容易的
剩下的兩種狀況更適合有明確自訂需求
或是希望完全自訂而非製作複合控制項的進階使用者
可以直接參考msdn上面的詳細說明

另外,如果希望在XAML裡面宣告自訂的元件的話
可以參考在WPF的XAML裡面使用自訂的控制項

--
參考資料
控制項撰寫概觀
WPF Gadget Container Control
自訂 Windows Presentation Foundation 控制項
試試看:建立自訂的 WPF 控制項

2009年8月24日 星期一

在C#中整理程式碼

在C++中因為宣告和實作可以分開
所以將同個類別的不同實作分寫成很多檔案很容易
只要所有的檔案同時include同樣的標頭(.h)檔案就可以了

不過在C#裡面因為宣告和實作沒辦法分開做
(除非你想寫interface,不過概念又不太一樣)
但是把所有的class都寫在一起又很複雜而難以閱讀
所以在C#裡面要整理程式碼有兩個工具

第一個就是用#region,#endregion將一部分的程式碼夾住
可以把同類型的程式,如變數宣告、事件處理、公開函式
分別寫在不同的region裡面

public class c1
{
#region var declaration

int i;

#endregion

#region public function

public void f1()
{
...
}

public void f2()
{
...
}

#endregion
}

之後就可以用visual studio的功能
將一部分的程式碼直接隱藏

public class c1
{
var declaration

public function
}

這對於程式可讀性來說相當重要
之後就可以針對需要閱讀或編輯的區塊展開來編輯就好

不過即使這樣,實際的檔案還是沒有變小
如果不是使用visual studio來檢視的時候就會很痛苦

所以這時候就要用到另外一個工具 - partial class
在C#裡面可以將類別(class)宣告成部分
所以可以將不同的部分宣告在不同的partial class裡面

public partial class c2
{
public void f1()
{
...
}
}

public partial class c2
{
public void f2()
{
...
}
}

在編譯的時候這些同樣名字的類別會被合在一起編譯
所以可以把同一個類別的個別函式宣告在不同的cs檔案裡
要注意每個檔案中要用同樣的namespace
只有相同namespace下的同名的partial class會被合併一起處理

另外補充一點
在WPF裡面,如果有使用XAML來配置class的一些內容
比如window或是application之類的
那class也必須宣告成partial
因為XAML也會被轉換成另外一個partial class
裡面包含像是InitializeComponent之類預設的function

--
參考資料
Partial Class Definitions (C# Programming Guide)
.NET 2.0四大金剛Partial Class

2009年8月19日 星期三

關閉視窗與關閉應用程式

在WPF的預設中,應用程式的關閉是在所有的視窗被關閉之後
但是對於習慣.net form上面的應用程式開發者來說
還是習慣使用單一視窗為主視窗,應用程式會隨之關閉
這時候可以將WPF的Application的XAML加入

<Application
...
MainWindow="Window1"
ShutdownMode="OnMainWindowClose">
<Application.Resources>
</Application.Resources>
</Application>

這時就算之後新增了很多視窗,但是Window1仍舊會導致程式關閉
如果到執行的一半需要更換主視窗(比如登入之後)
可以在Application的程式碼中(不是Window的~)

private void ChangeMainWindow(Window w)
{
MainWindow = w;
}

取得視窗關閉的理由 - CloseReason

在.net form預設的事件處理裡面有FormClosing

private void Form1_FormClosing(object sender,
FormClosingEventArgs e){...}

在視窗被關閉的時候會被啟動
e.CloseReason就是這個event發生的原因,常用如下
CloseReason說明
UserClosing使用者按下此form右上角的關閉按鈕
TaskManagerClosing用工作管理員強制關閉
WindowsShutDown關機的時候所觸發
UserClApplicationExitCallosing所從屬的應用程式被關閉時呼叫

此時可以針對不同的需求來做不同的處理
例如讓使用者做再一次的確認
並用e.Cancel抑制關閉事件的發生

private void Form1_FormClosing(object sender,
FormClosingEventArgs e)
{
/// if the close button in the title bar is clicked
if (e.CloseReason == CloseReason.UserClosing)
{
/// ask the user whether close or not
if (MessageBox.Show("Leave?", "warning",
MessageBoxButtons.YesNo) ==
DialogResult.No)
{
/// cancel the process of closing
e.Cancel = true;
}
}
}

但是到了WPF之後
Window的Closing事件和應用程式的關閉已經切開了
在Window的Closing事件中仍然可以被制止

private void Window_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
/// ask the user whether close or not
if (MessageBox.Show("Leave?", "warning",
MessageBoxButton.YesNo) ==
MessageBoxResult.No)
{
/// cancel the process of closing
e.Cancel = true;
}
}

但這時候已經沒有CloseReason可以選用了
因為單一視窗並不影響Application是否關閉
Application預設的關閉條件是最後的視窗被關閉
所以原先所提供的選項已經不再有意義

這時候如果仍然希望知道Application被關閉的原因
Application有提供SessionEnding事件
在Application的XAML裡面加上

<Application
...
SessionEnding="Application_SessionEnding">
<Application.Resources>
</Application.Resources>
</Application>

在程式碼中會看到

private void Application_SessionEnding(object sender,
SessionEndingCancelEventArgs e){...}

這時候可以從e.ReasonSessionEnding得到簡單的關閉原因

--
參考資料
WPF - Closing Application
表單右上角之關閉功能

2009年8月17日 星期一

在C#中可為null的型別,bool? int?

在C#中有些型別可以在原有的值域在加上null
而成為System.Nullable結構的執行個體,例如

Nullable<bool> b = null;

語法T?是Nullable<T>的簡略表示法,所以上面也可以表示成

bool? b = null;

把一個變數宣告成Nullable對於使用容許不宣告的變數很方便
不過在使用此型別的變數的時候需要特別小心
因為有時候並沒有被宣告(或是設成了null),所以在轉換成原有形別之前
需要先檢查是否有被設定

public bool ChangeToBool(bool? b)
{
/// check if b is null
if (b.HasValue)
{
return (bool)b;
}
else
{
return false;
}
}

另外,C#裡面也定義了更簡單的null聯合運算子??
所以上面的函式也可以直接寫成

public bool ChangeToBool(bool? b)
{
/// if b is null, return false, otherwise, return b
return b ?? false;
}

注意,透過null聯合運算子的結果就不需要再做型別轉換了
--
參考資料
可為 Null 的型別 (C# 程式設計手冊)
HOW TO:從 bool? 安全轉型至 bool (C# 程式設計手冊)
?? 運算子 (C# 參考)

2009年8月14日 星期五

UML - 活動圖 (Activity Diagram)

在循序圖裡面不容易表達狀況的分支
同一個時點可能會有多種選擇
而不同的選擇應該要接下去發展的情況就有所不同
這時候就要用活動圖來表示這些分支的狀況

一個循序圖有下面幾個元素
元素說明
初始狀態
(Initial state)
活動的起始點,全圖只會有一個,實心圓
最後狀態
(Final state)
活動的終止點,全圖至少一個,實心圓外包一個圓
動作狀態
(Action state)
代表一個動作,左右為弧線,上下為水平線,登入...
決策
(Decision)
代表情況的分歧,菱形
行動流
(Action flow)
動作之間的連續,實線箭頭
可加條件,以中括弧夾住
物件流
(Object flow)
物件之間的傳遞,虛線箭頭,此例圖中無
分叉(Fork)該狀態可以有多種行動,粗黑線段,一進多出
加入(Join)多種狀態都可以有該行動,粗黑線段,多進一出
此例圖中無

活動圖其實和流程圖很像
透過活動圖可以將整個系統的流程表達出來
也可以找出一些在循序圖中無法發現的分歧,避免遺漏

Blogger的插入圖片

在Blogger中使用預設的工具插入圖片
有時候會覺得照片看起來糊糊的
那是因為Blogger在上傳圖片的時候幫你做了兩件事

首先,如果圖檔的長或寬有一邊超過1600px
那他就會先幫你重新壓縮成1600為最大

第二,在顯示圖檔的時候,他會是以長邊為400的縮圖來顯示的
因為在選定的時候大小就只有200,320,400三種大小而已
這樣可以讓圖的載入速度變快,但是有時就會覺得畫質不好

在加入圖案的時候,選擇修改Html,可以看到原始碼

<a
onblur="
try {parent.deselectBloggerImageGracefully();}
catch(e) {}"
href="http://4.bp.blogspot.com/_7YTvBjsH78k/
SoT-IhmThfI/AAAAAAAAApM/Ax3wDbQ4uBw/s1600-h/
use+case+1.png">
<img
style="display:block; margin:0px auto 10px;
text-align:center;cursor:pointer;
cursor:hand; width: 400px; height: 320px;"
src="http://4.bp.blogspot.com/_7YTvBjsH78k/
SoT-IhmThfI/AAAAAAAAApM/Ax3wDbQ4uBw/s400/
use+case+1.png"
border="0"
alt=""
id="BLOGGER_PHOTO_ID_5369696078143915506"
/>
</a>

上面紅字的地方,就代表著使用400px的縮圖為來源
所以我們把它修改成s1600
就會是以最高解析度的原圖顯示了

--
參考資料
Blogger圖片大小的控制
Blogger上傳圖片的原始碼解析

UML - 循序圖 (Sequence Diagram)

在使用案例圖做完後,會發現我們要提供的系統該提供哪些功能
可是系統到底應該做些什麼來達到這些功能呢
這時候就需要循序圖(Sequence Diagram)來幫忙啦

循序圖最大的好處就是可以沿著時間軸
一步一步的將某個使用案例中,系統元件的訊息交換表現出來

一個循序圖至少有下面幾個元素
元素說明
角色
(Class role)
每個物件在系統中所扮演的角色,觀眾、訂票網頁、資料庫
生命線
(Lifeline)
角色存活的時間,角色下延伸的虛線
活動
(Activity)
角色處理一項操作需要的時間,覆蓋虛線的方框
訊息
(Message)
物件之間溝通的訊息,方框間的箭頭符號
* 一般傳輸、呼叫、回傳分別用不同的箭頭表示
* 使用者對介面的溝通常會在訊息前加上"/"以示區別

透過循序圖,開發者可以先構思每個物件該如何交換訊息
而且因為有時間軸的概念,循序圖可以表示一些事件應該發生的先後順序
這是靜態圖和使用案例圖無法達到的

另外,雖然循序圖基本上是對單一使用案例的單一情況
(使用者下的決定或環境狀況)來做描述
不過如果希望將多種可能同時畫在一張循序圖上
也可以在傳遞的訊息前加上[狀況]來表達某種情況下的處理方式
不同狀況的處理方式就可以放進同一張循序圖中了
有興趣的話可以參考Interaction Diagrams
不過基本上這種做法常會讓循序圖的時間軸亂掉
如果沒有把握的話不建議使用

2009年8月13日 星期四

在C#的結構(struct)中使用陣列(array)

C#是物件導向的語言,所以並不建議在其中使用結構
需要使用的時候最好儘量使用類別(class)來取代

不過有時候還是會需要定義結構,比如使用前人定義出的結構時
為了要和非.net(unmanagement)的程式庫(dll)溝通
還是需要定義出符合原本定義的結構,如果都只用到一些共通的形態的話
那在C#和C++中的定義基本上是一樣的

struct t1
{
char c;
int i;
};

不過這時候如果結構裡面有定義陣列的話

struct t2
{
char c;
int i[10];
};

因為C#裡面並沒有單純陣列的概念
所以基本上都要宣告成陣列物件

struct t2cs
{
char c;
int[] i;
};

這時候會發現沒辦法在這結構裡面直接宣告陣列的大小
因為物件不能在宣告的時候給值,必須要在new出物件的時候才能給定
記憶體的大小會跟非net的結構不同,所以傳遞過去也沒辦法取用

這時候可以使用unsafe和fixed來處理,
將這個程式區段設定為unmanagement的形態

unsafe struct t2cs
{
char c;
fixed int i[10];
};

雖然這種宣告方法很直覺
不過這樣的宣告需要去專案屬性裡面
將編譯選項裡面的容許unsafe選項打開
而且這個方法僅適用於一般形態的陣列(int, char...)
如果是結構的陣列就會出現問題

struct t3
{
char c;
t1 t[10];
};

那就沒辦法使用fixed來定義了
這時候可以用MarshalAs來預留一塊記憶體位置

struct t3cs
{
char c;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
t1[] t;
};

這時候如果發現兩邊的記憶體大小值不一樣的話
可以參考結構(struct)的大小問題來限定記憶體的配置方式
之後就可以直接接收物件來使用或是傳遞迴去了

--
參考資料
Fixed Size Buffers (C# Programming Guide)
[C#] Array in struct
Marshal Unmanaged struct to managed code using c#
UnmanagedType 列舉型別

2009年8月12日 星期三

在C#中傳回參數(out & ref)

因為C#裡面並不常使用指標的概念
所以在呼叫函式的時候,如果需要回傳多個值,會覺得無從下手
實際上C#裡面有定義out來幫助程式開發者傳回物件
用法很簡單,在宣告和呼叫的參數前都加上out就可以了

public void GetZero(out int i)
{
i = 0;
}

public void Call()
{
int i;
GetZero(out i);
}

注意,在這時候,由於宣告了參數是out的形態
所以在呼叫前可以不給值(給了值也會在呼叫的時候自動清掉)
但是在函數中一定要給值,否則會有錯誤(如同宣告了回傳值,卻沒有return)

另外,有時候會需要用到一個值,然後再將該值更新
那就需要用到ref了,一樣是在宣告和呼叫的時候都在參數前加上ref

public void AddOne(ref int i)
{
i++;
}

public void Call()
{
int i = 0;
AddOne(ref i);
}

注意,ref的參數必須在呼叫前給值(因為該值在函式中可能被使用到)
而且也可以在呼叫過程中更新(不更新也不會有錯誤)
--
參考資料
out (C# 參考)
ref (C# 參考)
C#中ref和out的使用小結

2009年8月11日 星期二

.net的日期時間物件

在System裡面就有DateTime類別可以用

/// current local time
DateTime now = DateTime.Now;

/// current time in Coordinated Universal Time (UTC)
DateTime unow = DateTime.UtcNow;

如果要自訂一個時間,也可以指定一個世界標準時間

DateTime d = new DateTime(
2000, /// year
8, /// month
12, /// day
17, /// hour
30, /// minute
0, /// second
DateTimeKind.Utc);

再用下面的方法與當地時間互相轉換

DateTime ld = d.ToLocalTime();
DateTime ud = ld.ToUniversalTime();

--
參考資料
DateTime 結構

2009年8月10日 星期一

UML的使用流程

因為UML就是一個工具箱,看什麼場合用什麼樣的工具
所以其實並沒有所謂的使用流程
但是對於初學者,還是可以遵照一個簡單的流程
步驟說明
使用者觀點利用使用個案圖,將使用者會直接用到的功能列出
行為觀點利用循序圖,表達每個使用個案的特定流程
利用活動圖,將循序圖泛化成一般活動流程
結構觀點利用類別圖,表達活動及循序圖中所用到的物件類別,包括變數、函式及其間相關性

根據UML的使用時機,UML是在設計階段之後
也就是已經將需求分析等事前準備工作都完成後
要將概念傳達給實作者的步驟
所以這整個塑模的流程,是在已經清楚的知道想要做出的成品時
將成品的概念利用塑模的工具一點點捏塑出來
而當類別圖建好之後,就已經可以開始實作了

UML的使用時機

初學者在使用UML的時候很容易迷失了方向
因為UML提供了太多的觀點而不知從何下手
這時候可以先從系統的開發角度來看
階段說明
設計分析需求,將需求分類,並針對有效的需求做出相應設計
實作針對設計出的模型,將需求實際的功能填入模型
評估根據實作出的成品,審視需求的滿足狀態

而UML的模型套用的地方,就是從設計階段到實作階段時
透過設計者(非工程師)與實作者(工程師)共同瞭解的表示法
有效的將設計的理念傳達出來
在評估階段,也可以透過當初設計者所制定的UML
確認實作者是否將設計者所想的都做了出來

另外,由於上面列的這段流程會是一個循環
從設計出發,實作、分析、修正設計、添加實作、重新分析...
透過螺旋式(Spiral model)的放大,一步步的進化成完成品
所以UML在使用上也會是這樣的進化
並不需要在一開始的時候就訂的非常完整
而是經過不同階段的實作及分析修改設計,漸漸的完善出來的

2009年8月6日 星期四

結構(struct)的大小問題

在記憶體配置的時候,因為效率考量,預設會依照元素大小整數倍的對齊
並且會以其中最大的元素為單位,配置整數倍的記憶體
例如同樣是char, short, int三個元素

struct t1
{
char c; /// 0000000x
short s; /// 0000xx00
int i; /// xxxx0000
};

struct t2
{
int i; /// 0000xxxx
short s; /// 00xx0000
char c; /// 0x000000
};

struct t3
{
short s; /// 0000000000xx
int i; /// 0000xxxx0000
char c; /// 000x00000000
};


這時候宣告出來的結構物件,大小會是8,8,12
在t1中的short,因為需要從偶數位置開始,所以會跳過1直接由2開始
而t3中的int則是因為需要從四的倍數開始,所以跳過2,3直接從4開始
三個結構的最大單元都是int,所以預留記憶體大小的時候都會是四的倍數

從上面的例子可以看出記憶體不連續的狀態,進而造成大小判斷錯誤
所以在宣告的時候最好依照大小作配置,才比較不會出現記憶體的空缺

不過,如果是對記憶體非常侷限的設備,為了避免記憶體的浪費
或是一些可讀性的考量,所以配置的方式並不能依照大小排列
這時候會需要將多出的記憶體空缺給填滿(改變對齊方式)
將struct宣告改寫成

#pragma pack(1) /// force alignment to 1 byte
struct t1
{
char c; /// 000000x
short s; /// 0000xx0
int i; /// xxxx000
};
#pragma pack() /// set alignment back to default

強制要求程式以1byte為單位對齊,大小就會變成7
並在宣告後,將預設的單位設回來(否則會出現warning)

如果是在C#裡面,則改成

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct t1
{
char c; /// 000000x
short s; /// 0000xx0
int i; /// xxxx000
};


--
參考資料
如何控制.NET Framework 2.0 中的資料欄位的實體配置
#pragma pack和數據對齊問題
C#-struct實例字段的內存佈局(Layout)和大小(Size)

2009年8月5日 星期三

UML - 使用個案圖 (Use Case Diagram)

在開始對一個系統塑模的時候,通常會先從使用個案圖開始
由非工程角度出發,確定該系統的設計範圍以及使用者會使用到的功能
也就是利用使用者的觀點取得一個視角,例如

一個使用案例圖至少有下面幾個元素
元素說明
動作者(actor)實際操作系統的人或外部系統,觀眾
使用案例(use case)系統提供的功能,動作越明確越好,訂票、取消
系統(system)實際上要開發的系統,訂票系統

由上面的例子可以看出,我們開發的訂票系統,使用對象是觀眾
可以操作的功能則有訂票和取消兩項
使用案例圖有時候還會用一些關聯性來模組化使用案例

關聯性說明
使用(uses)在過程中會使用到其它的使用案例,也稱做包含(include)
擴充(extend)在某條件成立下,會使用到其它的使用案例

如果系統是由多個人共同開發,透過使用案例圖
可以在制定細節前,預先讓開發者對於使用者可以有一致的瞭解
之後在開發的時候才有所依據

--
參考資料
從鳥瞰的觀點看 Use Case Diagram
使用案例圖的UML風格指南
Wikipedia - Use case diagram

2009年8月4日 星期二

UML的圖形種類

在UML2.0里面定義了13種圖(Diagrams)
結構性圖形(Structure Diagrams),系統式的建模
類別圖
(Class Diagram)
將系統中的類別列出,並描述出每個類別包含的屬性方法及類別間的關聯性
元件圖
(Component Diagram)
系統的實作觀點,系統中元件的互動、關連性及介面
複合結構圖(Composite Structure Diagram)系統中元件、類別或是使用案例的細節
部署圖
(Deployment Diagram)
系統的環境觀點,資源元素的組態及其與元件間的互動
物件圖
(Object Diagram)
類別的實作,通常是在某個時間點或某特定情況下的物件及其之間的交互關係
包圖
(Package Diagram)
顯示模型元素是如何包裝起來,以及這些包裝間的相依性
行為式圖形(Behavior Diagrams),事件觸髮式的建模
活動圖
(Activity Diagram)
單一類別對於內部處理作的反應,包含行動流及物件流
狀態機圖
(State Machine diagram)
單一物件的生命週期,顯示其與外界互動所造成的狀態改變
使用個案圖
(Use Case Diagram)
系統的使用者觀點,表示系統可以提供給每類互動者哪些功能
溝通性圖形(Interaction Diagrams),資料流程式的建模
行為圖形的子集合
通信圖
(Communication Diagram)
表示物件的相關性,以及其間的訊息流,也叫做合作圖(Collaboration Diagram)
交互概述圖(Interaction Overview Diagram)概觀系統的控制流,每個活動都可以再被表示成一個交互圖,2.0新增
循序圖
(Sequence Diagram)
顯示在時間序列中,類別訊息交換的順序
時間圖
(Timing Diagram)
物件受互動影響而造成的狀態改變過程(隨時間改變的狀態),2.0新增

在規畫塑模的時候,不一定全部都需要建立出來
依照系統的屬性以及需求,採用不同的面向才有意義

--
參考資料
維基百科 - 統一塑模語言(UML)
Introduction to the Diagrams of UML 2.0

UML概觀

UML可以用各種不同的面向來呈現或觀察一個系統
舉例來說,一台螢幕可以用這些面向來呈現
或許因為面向太多,所以很容易混淆而弄不清楚UML到底在幹嘛
面向呈現
功能呈現影像訊號、轉動改變視角、按鍵調整設定、觸控(選用)
結構背光模組、框架、接頭、按鍵、觸控模組(選用)
狀態開、關、調整畫面

我覺得應該不要把UML當成一種語言,而是一種溝通的工具
用一些大家約定好的記號來表示剛剛所提的這些面向
比如說一個橢圓、或是棒子人、一個方框...都代表特定的含意
在呈現與觀看的雙方都建立好同樣的背景知識後
才有辦法針對系統內可能會發生或已經發生的問題討論

對於大型系統開發尤其重要,越是耗費人力與時間的系統
越容易在過程中有共同開發甚至交接的狀況發生
大型系統耗費在溝通上的時間可能還超過開發的時間
這時候一個共通的溝通工具和已經制定好的模型就異常重要了

2009年8月3日 星期一

在Blog中自訂CSS標籤

如果在寫blog的時候需要換文字的顏色
又不希望每次還要切換成撰寫模式去填顏色
或是怕每次填的顏色可能會不一樣
那就自訂一個標籤吧

在css中設定標籤的地方加入

n1 {
color: rgb(51, 204, 0);
}

之後再需要的內容使用這個標籤夾住

<n1>/// notes 1<n1>

就可以將該內容改成你希望的格式

/// notes 1

在Blog中加入表格

在blog中如果將表格從別的軟體貼過來
常常格式會亂掉
如果變成圖片再貼過來又覺得解析度不太好
這時候就直接用html來製作表格吧

在設定css的地方,以Blogger為例
自訂->版面配置->修改HTML 找到

body {
...
}

然後加入

table {
border-collapse: separate;
border: 1px solid #999999;
width: 100%;
margin: 10px 0px 10px 0px;
}

th {
border: 1px solid #999999;
background-color: #eeeeee;
text-align: center;
}

td {
border: 1px solid #999999;
}

然後新增文章裡面直接修改html,加入

<table><th>標題1</th><th>標題2</th></tr><tr><td>內容1-1</td><td>內容2-1</td></tr><tr><td>內容1-2</td><td>內容2-2</td></tr></table>

就會變成
標題1標題2
內容1-1內容2-1
內容1-2內容2-2

注意,這裡不能換行,因為blogger會自動將換行符號
轉換成<br>,讓表格上方多出一堆空白

語法遵照CSS的標準

標籤參數說明
tableborder-collapse內框線與外框線分離
border框線的型態,設成細灰線
width寬度,設成填滿所在框架的寬度
margin外邊界,分別是上左下右邊界的寬度
thborder框線的型態,設成細灰線
background-color填滿色彩,設成淺灰色
text-align文字對齊方式,置中
tdborder框線的型態,設成細灰線

在Blog中加入程式碼方塊(code block)

在網頁或是blog中加入程式碼方塊
除非一開始選的範本裡面就有定義好
否則只能自己修改範本裡的css

以Blogger為例,在自訂->版面配置->修改HTML找到

code {
...
}

把整個換成

code {
white-space: pre;
display: block;
background: #eeeeee;
padding: 5px 5px 20px 5px;
margin: 5px;
}

這樣在發表文章的時候,直接點選修改html
將想要放在程式碼方塊中的內容,用code這個標籤夾住,像是

<code>
...
</code>

發佈之後就會看到

...

裡面的用法都是css的標準用法
參數說明
white-space縮排方式,可參考CSS white-space 屬性
display將標籤夾起的部分圍成一個區塊
background設定背景顏色,淺灰色
padding內邊界(上左下右),預設上方會多一行,所以下方設多一點
margin外邊界,讓區塊跟文字稍為隔開