2009年11月6日 星期五

在WPF中自訂形狀(Shape)

在WPF的UI設計中,有時候會需要特殊形狀的控制項
可以使用ImageBrush以及透明背景的一張圖
將控制項(如Border)繪製成不規則形狀
(參考在WPF中使用影像筆刷(ImageBrush))
但是這種做法有個缺點,就是實際上的控制項並不是不規則的
所以如果要做成鑲嵌在一起的一些控制項就會因為互相覆蓋而造成問題

第二種就是用現有的基本形狀(Shape),如方形、橢圓等組合成新的控制項
可以利用Union, Xor, Intersect, Exclude兩兩組合
從而做出許多變化,例如

<Path Fill="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Xor">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="50,50"
RadiusX="30"
RadiusY="30" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="100,50"
RadiusX="30"
RadiusY="30" />
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>

上面就是兩個圓直接做Xor,顯示出來的圖會是

這樣的做法雖然已經可以做出一些很特別的控制項了
但是畢竟彈性還是有限,所以同樣使用Path,還可以用更彈性的方法來做
將上述例子中的CombinedGeometry中換成PathGeometry

<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="True"
StartPoint="10,10">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Point="50,50"
Size="50,50"
SweepDirection="Clockwise"/>
<LineSegment Point="50,10" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>

同樣的效果也可以用C#寫

private Path AddShape()
{
/// set path with stroke
Path p = new Path();
p.Stroke = Brushes.Black;
p.StrokeThickness = 1;

/// set path figure with start and IsClosed
PathFigure pf = new PathFigure();
pf.IsClosed = true;
pf.StartPoint = new Point(10,10);

/// add two segments
pf.Segments.Add(new ArcSegment(
new Point(50,50), new Size(50,50), 0,
false, SweepDirection.Clockwise, true));
pf.Segments.Add(new LineSegment(
new Point(50,10), true));

/// set the data as the new path figure
p.Data = new PathGeometry();
(p.Data as PathGeometry).Figures.Add(pf);

return p;
}

在這邊的路徑片段(Segment)都代表從現在的點到一個點
然後構成一整條路徑,再將其填滿,可分成
種類說明
LineSegment直線段,只需設定目的點(Point),即會從目前所在連成一條直線段
ArcSegment弧線段,除目的點(Point)外,還需要設定弧形大小(Size,橢圓的長短軸)、軸旋轉角度(RotationAngle,預設為0)、線段轉彎方向(SweepDirection),以及是否轉彎超過180度(IsLargeArc)
PolyLineSegment多線段,設定一組連續的點(Points),即會從目前所在依照順序連接起來
BezierSegment三次貝茲曲線,設定目的點(Point3)以及兩個控制點(Point1, Point2)
PolyBezierSegment多段三次貝茲曲線,設定一組連續點(Points),其中每三個為一小組,代表經過兩控制點到目的點的一段三次貝茲曲線
QuadraticBezierSegment二次貝茲曲線,設定目的點(Point2)以及一個控制點(Point1)
PolyQuadraticBezierSegment多段二次貝茲曲線,設定一組連續點(Points),其中每兩個為一小組,代表經過控制點到目的點的一段二次貝茲曲線

--
參考資料
Path 類別
HOW TO:建立複合圖案
HOW TO:使用 PathGeometry 建立圖案
PathSegment 類別

在C#中自訂應用程式圖示(Icon)

寫應用程式在開發完之後
常常會希望自己的程式有一個不一樣的圖示以示區別
在工具列中找到專案->屬性

然後設定應用程式->資源->圖示和資訊清單,選擇"圖示"右邊的開檔按鈕

然後選擇自己喜歡的圖示檔(*.ico)即可

如果喜歡的圖示並不是ico格式,也可以用繪圖軟體(如GIMP, Freeware)
轉換格式(開啟後直接另存成ico檔案)即可使用

在WPF中使用漸層筆刷(GradientBrush)

在WPF中要達到漸層效果非常簡單
只要在想要展示漸層效果的地方使用漸層筆刷上色就可以了
筆刷的分類可見在WPF中的筆刷(Brush)

而漸層筆刷分為兩個實體類別
第一類是線性漸層(LinearGradientBrush)
也就是遵照一個線性的方向去漸層

<Rectangle>
<Rectangle.Fill>
<!--gradually change according a vector-->
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,0"
>
<GradientStop Offset="0" Color="Black" />
<GradientStop Offset="1" Color="White" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>

結果就像

StartPoint和EndPoint都是以該筆刷作用範圍的左上為(0,0),右下為(1,1)
除非想要做接合效果(好幾個物件像是連在一起),否則不會超出1
另外GradientStop.Offset是0-1之間的一個小數
相對於StartPoint為0,EndPoint為1的向量相對位置
上面的例子裡只有設起始點的顏色,所以就是單純的漸進
那如果增加一個

<GradientStop Offset="0.5" Color="Red" />

那就會變成

另外一類則是放射漸層(RadialGradientBrush)
也就是從一個點放射向外的漸層筆刷

<Rectangle>
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="0.5,0.5"
Center="0.5,0.5"
RadiusX="0.5"
RadiusY="0.5"
>
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="White" Offset="1" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

這裡面的座標跟線性漸層筆刷是一樣的
Center, RadiusX和RadiusY構成一個圓
然後從GradientOrigin為放射中心做出漸層

這邊的圓形會因為Brush作用的範圍而變形
另外,如果放射中心在圓的外面,那就會拉出一個椎形
比如將上面例子中的GradientOrigin改為"0,0"
那結果就會變成

--
參考資料
LinearGradientBrush 類別
RadialGradientBrush 類別

在WPF中使用影像筆刷(ImageBrush)

在WPF中可以透過筆刷的設定,將圖片直接畫在各種使用筆刷的物件上面
比如說在文字方塊設定背景

<TextBlock FontSize="50">
<TextBlock.Background>
<ImageBrush ImageSource="img.jpg" />
</TextBlock.Background>
</TextBlock>

那顯示出來的會是

這時候可以換成設定前景,也就是文字色彩

<TextBlock FontSize="50">
<TextBlock.Foreground>
<ImageBrush ImageSource="img.jpg" />
</TextBlock.Foreground>
</TextBlock>

那結果就會變成

透過這樣的動作就可以做出很多變化的介面
不過這邊要注意一個問題
就是使用影像筆刷的圖可以有透明的背景
畫出來的時候當然那些區域會是透明的,不過大小並不會改變
比如說當你將很多張透明背景的圖疊在一起的時候
下面的圖基本上是沒辦法接收到滑鼠事件的

--
參考資料
ImageBrush 類別

在WPF中的筆刷(Brush)

在WPF中的筆刷有很多種,常用的如下
筆刷說明
SolidColorBrush單色筆刷,可以用直接設定ARGB或是內建的Brushes
GradientBrush漸層筆刷,分為線性漸層(LinearGradientBrush)以及放射漸層(RadialGradientBrush)
ImageBrush影像筆刷,可以將一張圖片塗上某個物件的背景或前景
參考在WPF中使用影像筆刷(ImageBrush)
DrawingBrush可以包含圖案、影像、文字及媒體等繪圖物件
VisualBrush直接用視覺物件來繪製

筆刷可以用的地方其實很多,大部份的控制項都有背景(Background)
有些會有前景(Foreground, 如TextBlock)
還有些則是填滿(Fill, 如Retangle)
透過筆刷的交互作用,可以讓WPF的程式變得非常多變而彈性

--
參考資料
WPF 筆刷概觀