下面就是它的一些演示截圖。
首先是縮放,旋轉和透明處理:
然後是文字水印處理:
然後是使用Ink的塗鴨:
相信做爲一個相冊(圖片瀏覽)的基本功能已經沒什麼問題了。
下面來看一下這個DEMO的類圖,如下:
上圖中的左半部用紅框標識的區域是其控件設計類,因爲本DEMO中所使用的控件如:按鈕,滑動條,複選框等均未使用Silverlight中所提供的控件,而是自己繪製並定義事件。因此這是我對該DEMO感興趣的另一個原因。而右側則是一些工具類或圖片處理類,如處理圖片移動的MovableImage和TextBlock移動的
MovableTextBlock等。
下面先簡要介紹一下其中的Button按鈕控件的設計思路。因爲其繼承自ButtonBase,所以有必要先看一下ButtonBase的代碼聲明,下面是xaml中的內容:
<
ControlTemplate
xmlns
="http://schemas.microsoft.com/client/2007"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
>
<
Grid
x:Name
="Part_Root"
MouseEnter
="btnClearMouseEnter"
MouseLeave
="btnClearMouseLeave"
MouseLeftButtonDown
="btnClearMouseDown"
MouseLeftButtonUp
="btnClearMouseUp"
>
<
Grid.Resources
>
<
Storyboard
x:Name
="Part_MouseEnter"
/>
<
Storyboard
x:Name
="Part_MouseDown"
/>
<
Storyboard
x:Name
="Part_MouseUp"
/>
<
Storyboard
x:Name
="Part_MouseLeave"
/>
</
Grid.Resources
>
<
Rectangle
x:Name
="Part_BackgroundRect"
/>
<
TextBlock
x:Name
="Part_Caption"
/>
<
Rectangle
x:Name
="Part_ForegroundRect"
/>
<
Rectangle
x:Name
="Part_HighlightRect"
/>
</
Grid
>
</
ControlTemplate
>
從上面代碼可以看出其採用控件模版的方式進行定義。但其鼠標在按鈕上移入移出等狀態的Storyboard(故事板)並未進行定義。而肯體的實現被放在了相應的子類(Button.xaml和RepeatButton.xaml)進行實現。下面就是其中的Button.xaml內容:
<
ControlTemplate
xmlns
="http://schemas.microsoft.com/client/2007"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
>
<
Grid
x:Name
="Part_Root"
MouseEnter
="btnClearMouseEnter"
MouseLeave
="btnClearMouseLeave"
MouseLeftButtonDown
="btnClearMouseDown"
MouseLeftButtonUp
="btnClearMouseUp"
>
<
Grid.Resources
>
<
Storyboard
x:Name
="Part_MouseEnter"
>
<
ColorAnimation
Duration
="00:00:00.25"
To
="#3DFFFFFF"
Storyboard.TargetName
="Part_HighlightRect"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)"
/>
</
Storyboard
>
<
Storyboard
x:Name
="Part_MouseDown"
>
<
ColorAnimation
Duration
="00:00:00.2"
To
="#22000000"
Storyboard.TargetName
="Part_HighlightRect"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)"
/>
</
Storyboard
>
<
Storyboard
x:Name
="Part_MouseUp"
>
<
ColorAnimation
Duration
="00:00:00.2"
To
="#3DFFFFFF"
Storyboard.TargetName
="Part_HighlightRect"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)"
/>
</
Storyboard
>
<
Storyboard
x:Name
="Part_MouseLeave"
>
<
ColorAnimation
Duration
="00:00:00.25"
To
="#00FFFFFF"
Storyboard.TargetName
="Part_HighlightRect"
Storyboard.TargetProperty
="(Shape.Fill).(SolidColorBrush.Color)"
/>
</
Storyboard
>
</
Grid.Resources
>
<
Rectangle
x:Name
="Part_BackgroundRect"
StrokeThickness
="4"
RadiusX
="16"
RadiusY
="36"
Stroke
="#46000000"
>
<
Rectangle.Fill
>
<
LinearGradientBrush
EndPoint
="0.5,-0.4"
StartPoint
="0.5,1.4"
>
<
GradientStop
Color
="Gray"
Offset
="0.242"
/>
<
GradientStop
Color
="DarkBlue"
Offset
="0.333"
/>
</
LinearGradientBrush
>
</
Rectangle.Fill
>
</
Rectangle
>
<
TextBlock
x:Name
="Part_Caption"
VerticalAlignment
="Center"
HorizontalAlignment
="Center"
Foreground
="Gold"
Text
="Button"
>
<
TextBlock.RenderTransform
>
<
TranslateTransform
X
="0"
Y
="-2"
/>
</
TextBlock.RenderTransform
>
</
TextBlock
>
<
Rectangle
x:Name
="Part_ForegroundRect"
VerticalAlignment
="Top"
StrokeThickness
="4"
RadiusX
="16"
RadiusY
="36"
Width
="124"
Height
="32"
>
<
Rectangle.Fill
>
<
LinearGradientBrush
EndPoint
="0.5,-0.409"
StartPoint
="0.5,1.409"
>
<
GradientStop
Color
="#00FFFFFF"
Offset
="0.13"
/>
<
GradientStop
Color
="#FFFFFFFF"
Offset
="1"
/>
</
LinearGradientBrush
>
</
Rectangle.Fill
>
</
Rectangle
>
<
Rectangle
VerticalAlignment
="Top"
RadiusX
="16"
RadiusY
="36"
Fill
="#00FFFFFF"
x:Name
="Part_HighlightRect"
/>
</
Grid
>
</
ControlTemplate
>
注:這樣設計方式本人感覺很有意思,很有「面向對象」的味道,呵呵。
下面簡要瀏覽一下ButtonBase.xaml.cs的代碼:
[TemplatePart(Name
=
"
Part_Root
"
, Type
=
typeof
(Panel))]
[TemplatePart(Name
=
"
Part_Caption
"
, Type
=
typeof
(TextBlock))]
[TemplatePart(Name
=
"
Part_ForegroundRect
"
, Type
=
typeof
(Rectangle))]
[TemplatePart(Name
=
"
Part_BackgroundRect
"
, Type
=
typeof
(Rectangle))]
[TemplatePart(Name
=
"
Part_HighlightRect
"
, Type
=
typeof
(Rectangle))]
[TemplatePart(Name
=
"
Part_MouseEnter
"
, Type
=
typeof
(Storyboard))]
[TemplatePart(Name
=
"
Part_MouseLeave
"
, Type
=
typeof
(Storyboard))]
[TemplatePart(Name
=
"
Part_MouseDown
"
, Type
=
typeof
(Storyboard))]
[TemplatePart(Name
=
"
Part_MouseUp
"
, Type
=
typeof
(Storyboard))]
public
abstract
partial
class
ButtonBase : Control
{
///
<summary>
///
定義單擊事件
///
</summary>
public
event
EventHandler Click;
///
<summary>
///
執行單擊事件的綁定方法
///
</summary>
protected
void
OnClick()
{
if
(Click
!=
null
)
{
Click(
this
,
new
EventArgs());
}
}
///
<summary>
///
標題屬性
///
</summary>
public
string
Caption
{
get
{
return
this
.Part_Caption.Text; }
set
{
this
.Part_Caption.Text
=
value; }
}
///
<summary>
///
鼠標移入控件區域時啓動Part_MouseEnter故事板,下面類似
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
protected
virtual
void
Part_Root_MouseEnter(
object
sender, MouseEventArgs e)
{
Part_MouseEnter.Begin();
}
protected
virtual
void
Part_Root_MouseLeave(
object
sender, MouseEventArgs e)
{
Part_MouseLeave.Begin();
}
protected
virtual
void
Part_Root_MouseLeftButtonDown(
object
sender, MouseButtonEventArgs e)
{
Part_MouseDown.Begin();
}
protected
virtual
void
Part_Root_MouseLeftButtonUp(
object
sender, MouseButtonEventArgs e)
{
Part_MouseUp.Begin();
//
執行單擊事件的綁定方法
OnClick();
}
protected
Storyboard Part_MouseEnter, Part_MouseDown, Part_MouseLeave, Part_MouseUp;
protected
Rectangle Part_ForegroundRect, Part_BackgroundRect, Part_HighlightRect;
protected
Panel Part_Root;
protected
TextBlock Part_Caption;
}
其實上面的代碼與我們平時寫.net控件類似,也是屬性事件的定義。當然不同的地方就是對故事板的使用,
而故事板會讓我們的按鈕在鼠標觸發事件時在UI上看起來更酷。當然下面還要看一下相應的Button中的內容,因
爲這纔是實際運行時使用的控件,其代碼如下:
public
partial
class
Button : ButtonBase
{
public
Button()
{
//
加載Button.xaml中的內容,爲下面獲取元素進行相應操作
string
xaml
=
ResourceHelper.GetTemplate(
this
.GetType());
ControlTemplate template
=
(ControlTemplate)XamlReader.Load(xaml);
this
.Template
=
template;
this
.ApplyTemplate();
}
///
<summary>
///
對當前模板(xaml)中的元素進行(主要是鼠標)事件綁定
///
</summary>
public
override
void
OnApplyTemplate()
{
Part_Root
=
(Panel)GetTemplateChild(
"
Part_Root
"
);
Part_Caption
=
(TextBlock)GetTemplateChild(
"
Part_Caption
"
);
Part_ForegroundRect
=
(Rectangle)GetTemplateChild(
"
Part_ForegroundRect
"
);
Part_BackgroundRect
=
(Rectangle)GetTemplateChild(
"
Part_BackgroundRect
"
);
Part_HighlightRect
=
(Rectangle)GetTemplateChild(
"
Part_HighlightRect
"
);
Part_MouseEnter
=
(Storyboard)GetTemplateChild(
"
Part_MouseEnter
"
);
Part_MouseLeave
=
(Storyboard)GetTemplateChild(
"
Part_MouseLeave
"
);
Part_MouseDown
=
(Storyboard)GetTemplateChild(
"
Part_MouseDown
"
);
Part_MouseUp
=
(Storyboard)GetTemplateChild(
"
Part_MouseUp
"
);
Part_Root.SizeChanged
+=
new
SizeChangedEventHandler(Part_Root_SizeChanged);
Part_Root.MouseEnter
+=
new
MouseEventHandler(Part_Root_MouseEnter);
Part_Root.MouseLeave
+=
new
MouseEventHandler(Part_Root_MouseLeave);
Part_Root.MouseLeftButtonDown
+=
new
MouseButtonEventHandler(Part_Root_MouseLeftButtonDown);
Part_Root.MouseLeftButtonUp
+=
new
MouseButtonEventHandler(Part_Root_MouseLeftButtonUp);
}
///
<summary>
///
按鈕的實際高度或寬度發生變化時的處理事件
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Root_SizeChanged(
object
sender, SizeChangedEventArgs e)
{
Part_ForegroundRect.Width
=
Part_Root.ActualWidth
-
16d;
Part_ForegroundRect.Height
=
Part_Root.ActualHeight
-
12d;
Part_HighlightRect.Width
=
Part_Root.ActualWidth
-
10d;
Part_HighlightRect.Height
=
Part_Root.ActualHeight
-
8d;
if
(Part_Root.ActualWidth
>
Part_Root.ActualHeight)
{
Part_BackgroundRect.RadiusX
=
Part_ForegroundRect.RadiusX
=
Part_HighlightRect.RadiusX
=
Part_Root.ActualHeight
/
2d;
Part_BackgroundRect.RadiusY
=
Part_ForegroundRect.RadiusY
=
Part_HighlightRect.RadiusY
=
Part_Root.ActualWidth
/
4d;
}
else
{
Part_BackgroundRect.RadiusX
=
Part_ForegroundRect.RadiusX
=
Part_HighlightRect.RadiusX
=
Part_Root.ActualHeight
/
4d;
Part_BackgroundRect.RadiusY
=
Part_ForegroundRect.RadiusY
=
Part_HighlightRect.RadiusY
=
Part_Root.ActualWidth
/
2d;
}
}
}
到這裏還有另一個按鈕控件RepeatButton沒有介紹,其實它的內容也上面的Button代碼相似,所以就不多介紹了。
當然RepeatButton最終的用處是被放在了ImageSelector控件中做爲子控制被加載,這其中與我們開發「複合型」控件
相似。
下面就是Button控制的運行效果,如下所示:
當然這個DEMO在控件開發上還有一些有特色的地方,比如CheckBox控件等,我會在接下來的文章中加以說明,
呵呵。
好了,今天的內容就先到這裏了。
本文轉自 daizhenjun 51CTO博客,原文鏈接:http://blog.51cto.com/daizhj/100970,如需轉載請自行聯繫原作者