在
上一篇文章中,介绍了CheckBox控件的开发方式,包括xaml和控件逻辑(cs代码控制xaml中UI元素)。
本文所要介绍的Slider控件在xaml上与CheckBox复杂度相似,比较底。而控件逻辑相对要复杂不少,这些
逻辑会在本文中进行介绍。
好了,开始今天的正文。
首先看一下这个演示页,如下:
注:因为我从网上所获得的源码中Slider控件并没有全部开发完,起码在上面所示的垂直Slider只是粗
略的定义了xaml(其中某些值还有错误),而CS代码就少得更多了。本人在原有代码基础上,完成了垂直
Slider的开发,并修正了原有的CS代码中的BUG。
而该控件的xaml代码如下所示(Slider.xaml):
<
ControlTemplate
xmlns
="http://schemas.microsoft.com/client/2007"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
>
<
Grid
x:Name
="Part_Root"
Width
="200"
Height
="24"
>
<
Canvas
x:Name
="Part_Border"
Background
="Transparent"
>
<
Line
x:Name
='Part_Line'
StrokeThickness
="1"
Stroke
="Blue"
X1
="4"
X2
="196"
Y1
="12"
Y2
="12"
/>
<
Path
x:Name
='Part_ThumbHorizontal'
Canvas.Top
='3'
Data
='M0,0 L16,0 L8,18z'
Fill
='Silver'
Stroke
='Black'
/>
<
Path
x:Name
='Part_ThumbVertical'
Canvas.Left
='3'
Visibility
="Collapsed"
Data
='M0,0 L18,8 L0,16z'
Fill
='Silver'
Stroke
='Black'
/>
</
Canvas
>
</
Grid
>
</
ControlTemplate
>
从上面代码可以看出,Slider由四个主要元素组成:
Part_Border:用于绘制背景色(如ColorSlider控件的背景色)
Part_Line:用于绘制滑动的中线
Part_ThumbHorizontal:用于绘制水平滑块
Part_ThumbVertical:用于绘制垂直滑块
下面这张图标识了各元素在控件中的对应位置和关系:
对应上图,下面是ColorSlider的xaml代码:
<
ControlTemplate
xmlns
="http://schemas.microsoft.com/client/2007"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
>
<
Grid
x:Name
="Part_Root"
Width
='200'
Height
='24'
>
<
Canvas
x:Name
='Part_Border'
>
<
Canvas.Background
>
<
LinearGradientBrush
x:Name
="GradientBrush"
StartPoint
="0,0"
EndPoint
="1,0"
>
<
GradientStop
Color
="#FF000000"
Offset
="0"
/>
<
GradientStop
Color
="#FFFF0000"
Offset
="0.143"
/>
<
GradientStop
Color
="#FF00FF00"
Offset
="0.286"
/>
<
GradientStop
Color
="#FF0000FF"
Offset
="0.429"
/>
<
GradientStop
Color
="#FF00FFFF"
Offset
="0.571"
/>
<
GradientStop
Color
="#FFFF00FF"
Offset
="0.714"
/>
<
GradientStop
Color
="#FFFFFF00"
Offset
="0.857"
/>
<
GradientStop
Color
="#FFFFFFFF"
Offset
="1"
/>
</
LinearGradientBrush
>
</
Canvas.Background
>
<
Line
x:Name
='Part_Line'
StrokeThickness
="1"
Stroke
="Blue"
X1
="4"
X2
="196"
Y1
="12"
Y2
="12"
/>
<
Path
x:Name
='Part_ThumbHorizontal'
Canvas.Top
='3'
Data
='M0,0 L16,0 L8,18z'
Fill
='Silver'
Stroke
='Black'
/>
<
Path
x:Name
='Part_ThumbVertical'
Canvas.Left
='3'
Visibility
="Collapsed"
Data
='M0,0 L18,8 L0,16z'
Fill
='Silver'
Stroke
='Black'
/>
</
Canvas
>
</
Grid
>
</
ControlTemplate
>
说完了xaml,下面开始介绍cs控件逻辑代码。
首先要说的是一个枚举类型,用于标识滑动方向(垂直或水平):
///
<summary>
///
滑动条方向类型
///
</summary>
public
enum
SliderOrientation
{
///
<summary>
///
垂直
///
</summary>
Vertical,
///
<summary>
///
水平
///
</summary>
Horizontal
}
而控件的核心代码如下(有关我修改或添加的部分已通过注释说明):
///
<summary>
///
滑动条控制类
///
</summary>
[TemplatePart(Name
=
"
Part_Root
"
, Type
=
typeof
(Panel))]
[TemplatePart(Name
=
"
Part_Border
"
, Type
=
typeof
(FrameworkElement))]
[TemplatePart(Name
=
"
Part_ThumbHorizontal
"
, Type
=
typeof
(FrameworkElement))]
[TemplatePart(Name
=
"
Part_ThumbVertical
"
, Type
=
typeof
(FrameworkElement))]
[TemplatePart(Name
=
"
Part_Line
"
, Type
=
typeof
(FrameworkElement))]
public
partial
class
Slider : Control
{
public
Slider()
{
string
xaml
=
ResourceHelper.GetTemplate(
this
.GetType());
ControlTemplate template
=
(ControlTemplate)XamlReader.Load(xaml);
this
.Template
=
template;
this
.ApplyTemplate();
}
public
event
EventHandler ValueChanged;
///
<summary>
///
值改变时
///
</summary>
protected
void
OnValueChanged()
{
if
(ValueChanged
!=
null
)
{
//
执行绑定代码
ValueChanged(
this
,
new
EventArgs());
}
}
///
<summary>
///
绑定模板元素及相应事件
///
</summary>
public
override
void
OnApplyTemplate()
{
Part_Root
=
(Panel)GetTemplateChild(
"
Part_Root
"
);
Part_Line
=
(Line)GetTemplateChild(
"
Part_Line
"
);
Part_ThumbHorizontal
=
(FrameworkElement)GetTemplateChild(
"
Part_ThumbHorizontal
"
);
Part_ThumbVertical
=
(FrameworkElement)GetTemplateChild(
"
Part_ThumbVertical
"
);
Part_Border
=
(FrameworkElement)GetTemplateChild(
"
Part_Border
"
);
Part_ThumbHorizontal.MouseLeftButtonDown
+=
new
MouseButtonEventHandler(Part_Thumb_MouseLeftButtonDown);
Part_ThumbHorizontal.MouseMove
+=
new
MouseEventHandler(Part_Thumb_MouseMove);
Part_ThumbHorizontal.MouseLeftButtonUp
+=
new
MouseButtonEventHandler(Part_Thumb_MouseLeftButtonUp);
Part_ThumbVertical.MouseLeftButtonDown
+=
new
MouseButtonEventHandler(Part_Thumb_MouseLeftButtonDown);
Part_ThumbVertical.MouseMove
+=
new
MouseEventHandler(Part_Thumb_MouseMove);
Part_ThumbVertical.MouseLeftButtonUp
+=
new
MouseButtonEventHandler(Part_Thumb_MouseLeftButtonUp);
Part_Root.MouseLeave
+=
new
MouseEventHandler(Part_Root_MouseLeave);
Part_Root.MouseEnter
+=
new
MouseEventHandler(Part_Root_MouseEnter);
Part_Border.MouseLeftButtonDown
+=
new
MouseButtonEventHandler(Part_Border_MouseLeftButtonDown);
}
///
<summary>
///
当鼠标在滑动条(不是滑块)上点击时,将滑块设置到鼠标点击位置
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Border_MouseLeftButtonDown(
object
sender, MouseButtonEventArgs e)
{
//
当不是滑块时
if
(e.Source
!=
Part_ThumbHorizontal
&&
e.Source
!=
Part_ThumbVertical)
{
Point newPos
=
e.GetPosition(Part_Root);
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
Part_ThumbHorizontal.SetValue(Canvas.LeftProperty, Math.Min(newPos.X,
Part_Border.ActualWidth
-
Part_ThumbHorizontal.ActualWidth));
}
else
{
Part_ThumbVertical.SetValue(Canvas.TopProperty, Math.Min(newPos.Y,
Part_Border.ActualHeight
-
Part_ThumbVertical.ActualHeight));
}
this
.OnValueChanged();
}
}
}
///
<summary>
///
鼠标进入滑动条区域
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Root_MouseEnter(
object
sender, MouseEventArgs e)
{
if
(hasCapture)
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
Part_ThumbHorizontal.CaptureMouse();
}
else
{
Part_ThumbVertical.CaptureMouse();
}
}
else
{
_mouseDownValue
=
-
1
;
}
}
///
<summary>
///
鼠标离开滑动条区域
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Root_MouseLeave(
object
sender, MouseEventArgs e)
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
Part_ThumbHorizontal.ReleaseMouseCapture();
}
else
{
Part_ThumbVertical.ReleaseMouseCapture();
}
}
///
<summary>
///
鼠标按下滑动块
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Thumb_MouseLeftButtonDown(
object
sender, MouseButtonEventArgs e)
{
FrameworkElement thumb
=
(FrameworkElement)sender;
//
在当前滑动块上设置“鼠标捕获”
thumb.CaptureMouse();
hasCapture
=
true
;
_thumbMouseDown
=
e.GetPosition(Part_Root);
if
(_orientation
==
SliderOrientation.Horizontal)
//
当为水平方向时
{
//
获取滑动块的“左”值属性
_mouseDownValue
=
(
double
)thumb.GetValue(Canvas.LeftProperty);
}
else
{
//
获取滑动块的“顶”值属性
_mouseDownValue
=
(
double
)thumb.GetValue(Canvas.TopProperty);
}
}
///
<summary>
///
鼠标拖动滑动块移动
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Thumb_MouseMove(
object
sender, MouseEventArgs e)
{
FrameworkElement thumb
=
(FrameworkElement)sender;
Point newPos
=
e.GetPosition(Part_Root);
if
(_orientation
==
SliderOrientation.Horizontal)
{
double
newX
=
newPos.X
-
_thumbMouseDown.X
+
_mouseDownValue;
if
(_mouseDownValue
!=
-
1
&&
newX
<=
Part_Border.ActualWidth
-
8
&&
newX
>=
-
8
)
{
thumb.SetValue(Canvas.LeftProperty, newX);
//
仅在水平方向上移动
this
.OnValueChanged();
}
}
else
{
double
newY
=
newPos.Y
-
_thumbMouseDown.Y
+
_mouseDownValue;
if
(_mouseDownValue
!=
-
1
&&
newY
<=
Part_Border.ActualHeight
-
8
&&
newY
>=
-
8
)
{
thumb.SetValue(Canvas.TopProperty, newY);
//
仅在垂直方向上移动
this
.OnValueChanged();
}
}
}
///
<summary>
///
鼠标拖动结束
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
void
Part_Thumb_MouseLeftButtonUp(
object
sender, MouseButtonEventArgs e)
{
FrameworkElement thumb
=
(FrameworkElement)sender;
_mouseDownValue
=
-
1
;
thumb.ReleaseMouseCapture();
hasCapture
=
false
;
}
///
<summary>
///
设置滑动条的宽
///
</summary>
public
double
SliderWidth
{
get
{
return
Part_Root.Width; }
set
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
//
水平方向上设置
Part_Line.X2
=
value;
Part_Root.Width
=
value;
}
else
{
//
获取Slider.xaml中的相应属性配置
Part_Line.X1
=
Part_Line.X2
=
value
/
2d;
Part_ThumbVertical.SetValue(Canvas.LeftProperty, value
/
2d
-
Part_ThumbVertical.ActualWidth
/
2d);
}
}
}
///
<summary>
///
设置滑动条的高度
///
</summary>
public
double
SliderHeight
{
get
{
return
Part_Root.Height; }
set
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
//
获取Slider.xaml中的相应属性配置
Part_Line.Y1
=
Part_Line.Y2
=
value
/
2d;
Part_ThumbHorizontal.SetValue(Canvas.TopProperty, value
/
2d
-
Part_ThumbHorizontal.ActualHeight
/
2d);
}
else
{
//
垂直方向上设置
Part_Line.Y2
=
value;
Part_Root.Height
=
value;
}
}
}
///
<summary>
///
获取或设置滑动条的当前值
///
</summary>
public
double
Value
{
get
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
double
val
=
(
double
)Part_ThumbHorizontal.GetValue(Canvas.LeftProperty)
/
(Part_Root.ActualWidth
-
8
);
val
=
Math.Max(0d, val);
val
=
Math.Min(val, 1d);
return
val;
}
else
{
double
val
=
(
double
)Part_ThumbVertical.GetValue(Canvas.TopProperty)
/
(Part_Root.ActualHeight
-
8
);
val
=
Math.Max(0d, val);
val
=
Math.Min(val, 1d);
return
val;
}
}
set
{
if
(_orientation
==
SliderOrientation.Horizontal)
{
Part_ThumbHorizontal.SetValue(Canvas.LeftProperty, value
*
(Part_Root.Width
-
8
));
}
else
{
Part_ThumbVertical.SetValue(Canvas.TopProperty, value
*
(Part_Root.Height
-
8
));
}
}
}
///
<summary>
///
获取或设置滑动条的方向,参见SliderOrientation
///
</summary>
public
SliderOrientation Orientation
{
get
{
return
_orientation; }
set
{
_orientation
=
value;
if
(_orientation
==
SliderOrientation.Horizontal)
{
Part_ThumbVertical.Visibility
=
Visibility.Collapsed;
Part_ThumbHorizontal.Visibility
=
Visibility.Visible;
Part_Line.Y1
=
Part_Line.Y2
=
Part_Root.Height
/
2d;
Part_Line.X1
=
0d;
Part_Line.X2
=
Part_Root.Width;
}
else
{
//
注:此处代码为本人所加,用于当为垂直方向时,交换Width与Height的值
double
temp
=
Part_Root.Width;
Part_Root.Width
=
Part_Root.Height;
Part_Root.Height
=
temp;
Part_ThumbHorizontal.Visibility
=
Visibility.Collapsed;
Part_ThumbVertical.Visibility
=
Visibility.Visible;
Part_Line.X1
=
Part_Line.X2
=
Part_Root.Width
/
2d;
Part_Line.Y1
=
0d;
Part_Line.Y2
=
Part_Root.Height;
}
}
}
#region
UI元素声明
protected
Panel Part_Root;
protected
Line Part_Line;
protected
FrameworkElement Part_Border, Part_ThumbVertical, Part_ThumbHorizontal;
#endregion
protected
Point _thumbMouseDown;
protected
double
_mouseDownValue
=
-
1
;
protected
bool
hasCapture
=
false
;
protected
SliderOrientation _orientation
=
SliderOrientation.Horizontal;
}
下面代介绍的是ColorSlider控件的控件逻辑cs文件(详情看注释):
///
<summary>
///
颜色滑动条控制
///
</summary>
public
partial
class
ColorSlider : Slider
{
public
ColorSlider()
{
string
xaml
=
ResourceHelper.GetTemplate(
this
.GetType());
ControlTemplate template
=
(ControlTemplate)XamlReader.Load(xaml);
this
.Template
=
template;
base
.ApplyTemplate();
}
///
<summary>
///
该方法为本人所加,用户当滑动条方向为“垂直”时,重新设置“GradientBrush”的“EndPoint”属性
///
</summary>
public
new
SliderOrientation Orientation
{
get
{
return
base
.Orientation; }
set
{
base
.Orientation
=
value;
//
当为垂直方向时
if
(value
==
SliderOrientation.Vertical)
{
((LinearGradientBrush)GetTemplateChild(
"
GradientBrush
"
)).EndPoint
=
new
Point(
0
,
1
);
}
}
}
///
<summary>
///
获取颜色值
///
</summary>
///
<returns></returns>
public
Color GetColor()
{
return
this
.GetColor(
255
);
}
///
<summary>
///
将滑动条值(Value)转换为ARGB 颜色值并返回
///
</summary>
///
<param name="alpha">
alpha通道,该值介于0到255
</param>
///
<returns>
ARGB 颜色值
</returns>
public
Color GetColor(
byte
alpha)
{
Color color;
double
value
=
this
.Value;
//
将滑动条的值转换为 ARGB 颜色值
if
(value
<
0.143d
)
{
color
=
Color.FromArgb(alpha, (
byte
)Math.Floor((value
*
256d)
/
0.143d
),
0
,
0
);
}
else
if
(value
<
0.286d
)
{
color
=
Color.FromArgb(alpha, (
byte
)Math.Floor(256d
*
(
0.286d
-
value)
/
0.143d
),
(
byte
)Math.Floor(256d
*
(value
-
0.143d
)
/
0.143d
),
0
);
}
else
if
(value
<
0.429
)
{
color
=
Color.FromArgb(alpha,
0
, (
byte
)Math.Floor(256d
*
(
0.429d
-
value)
/
0.143d
),
(
byte
)Math.Floor(256d
*
(value
-
0.286d
)
/
0.143d
));
}
else
if
(value
<
0.571
)
{
color
=
Color.FromArgb(alpha,
0
, (
byte
)Math.Floor(256d
*
(value
-
0.429d
)
/
0.143d
),
255
);
}
else
if
(value
<
0.714
)
{
color
=
Color.FromArgb(alpha, (
byte
)Math.Floor(256d
*
(value
-
0.571d
)
/
0.143d
),
(
byte
)Math.Floor(256d
*
(
0.714d
-
value)
/
0.143d
),
255
);
}
else
if
(value
<
0.857
)
{
color
=
Color.FromArgb(alpha,
255
, (
byte
)Math.Floor(256d
*
(value
-
0.714d
)
/
0.143d
),
(
byte
)Math.Floor(256d
*
(
0.857d
-
value)
/
0.143d
));
}
else
{
color
=
Color.FromArgb(alpha,
255
,
255
, (
byte
)Math.Floor(256d
*
(value
-
0.857d
)
/
0.143d
));
}
return
color;
}
}
接着再来看一下如何使用这两个控件(也就是本文第一张图所演示的效果),其page逻辑代码如下:
public
partial
class
Page2 : UserControl
{
public
Page2()
{
InitializeComponent();


#region
Slider测试代码,加载图片并添加演示缩放旋转的Transform
string
baseUri
=
Application.Current.Host.Source.AbsoluteUri.Substring(
0
,
Application.Current.Host.Source.AbsoluteUri.LastIndexOf(
"
/
"
));
currentImage.SetValue(Image.SourceProperty,
new
BitmapImage(
new
Uri(String.Concat(baseUri,
"
/../Images/j0433157.jpg
"
))));
TransformGroup transforms
=
new
TransformGroup();
transforms.Children.Add(
new
ScaleTransform());
transforms.Children.Add(
new
RotateTransform());
currentImage.RenderTransform
=
transforms;
currentImage.RenderTransformOrigin
=
new
Point(
0.5
,
0.5
);
#endregion
}
#region
Slider示例代码
void
ColorSlider_ValueChanged(
object
sender, EventArgs e)
{
//
水平Slider设置背景色
SliderPanel.Background
=
new
SolidColorBrush(ColorSlider.GetColor());
}
void
ColorSlider2_ValueChanged(
object
sender, EventArgs e)
{
//
垂直Slider设置背景色
SliderPanel2.Background
=
new
SolidColorBrush(ColorSlider2.GetColor());
}
private
void
opacitySlider_ValueChanged(
object
sender, EventArgs e)
{
//
设置图像的Opacity属性
currentImage.Opacity
=
1d
-
opacitySlider.Value;
}
private
void
transformSlider_ValueChanged(
object
sender, EventArgs e)
{
//
设置旋转属性
((RotateTransform)((TransformGroup)currentImage.RenderTransform).Children[
1
]).Angle
=
(transformSlider.Value
-
0.5d
)
*
720d;
//
设置缩放属性
((ScaleTransform)((TransformGroup)currentImage.RenderTransform).Children[
0
]).ScaleX
=
transformSlider.Value
*
2d;
((ScaleTransform)((TransformGroup)currentImage.RenderTransform).Children[
0
]).ScaleY
=
transformSlider.Value
*
2d;
}
#endregion
}
好了,今天的内容就先到这里了。
tag:silverlight,slider,colorslider,imagesnipper
作者:代震军,daizhj
原文链接:http://www.cnblogs.com/daizhj/archive/2008/09/04/1284228.html
源码下载,请
点击这里:)