本篇实际上就是MSDN上HOL的实现。不过一开始没找到那个HOL源码下载,于是自己做了一个,改了些功能和设计。本身并不复杂,程序的效果就是可以在窗口的一个区域上添加各种RenderTransform样式图片图片,用户能够通过鼠标对每一张图片进行拖拽和缩放,拖拽的图片能够被置顶。看下效果:
呵呵就是个山寨的“传统版智能照片桌面”。
设计说明
相当于做一个User Control,遵循MVVM,对外提供ViewModel接口,暴露ViewModel属性(因为我一开始把ViewModel提出来了,设置ViewModel属性会自动设置DataContext)。出于演示目的,只写了演示用到的功能,望大家谅解
TouchFirst.SaApp:WPF程序宿主,这里充当一个测试控件的程序。
TouchFirst.ControlsLib:控件库,含有两个控件:ImageDecorator,ImagesTable以及对外暴露的ViewModel接口。
用到了”Sa.Wpf.mvvm.ViewModel.dll”中的ViewModelBase类,这是以前写的一个ViewModel基类,实现INotifyPropertyChanged、IDispose。
类型说明
ImageDecorator:简单包装一个Image控件,方便使用者直接配置RotateTransform的Angle等属性。
IImageDecoratorViewModel:ImageDecorator适用的ViewModel,方便MVVM开发中使用。
ImageTables:能够承载若干个ImageDecorator,提供一个AddImage方法用于使用者添加图片。
IInputSupport:负责注册ImageTables的事件以及相应添加图片操作。
TraditionalInputSupport:实现IInputSupport,使控件支持传统的操作方式。
MultitouchSupport:实现IInputSupport,使控件支持触控操作方式
细节说明
ImageDecorator.xaml
<
UserControl x:Class
=
"
TouchFirst.ControlsLib.ImageDecorator
"
xmlns
=
"
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x
=
"
http://schemas.microsoft.com/winfx/2006/xaml
"
Background
=
"
Transparent
"
>
<
Image x:Name
=
"
Img
"
Source
=
"
{Binding Path=ImagePath}
"
Stretch
=
"
Fill
"
Height
=
"
Auto
"
Width
=
"
Auto
"
RenderTransformOrigin
=
"
0.5, 0.5
"
>
<
Image.RenderTransform
>
<
TransformGroup
>
<
RotateTransform Angle
=
"
{Binding Path=Angle}
"
></
RotateTransform
>
<
ScaleTransform ScaleX
=
"
{Binding Path=ScaleX}
"
ScaleY
=
"
{Binding Path=ScaleY}
"
></
ScaleTransform
>
<
TranslateTransform X
=
"
{Binding Path=X}
"
Y
=
"
{Binding Path=Y}
"
></
TranslateTransform
>
</
TransformGroup
>
</
Image.RenderTransform
>
</
Image
>
</
UserControl
>
使用绑定时所要遵循的接口
IImageDecoratorViewModel
namespace
TouchFirst.ControlsLib
{
public
interface
IImageDecoratorViewModel
{
#region
Presentation Properties Contract
ImageSource ImagePath {
get
;
set
; }
double
ScaleX {
get
;
set
; }
double
ScaleY {
get
;
set
; }
double
X {
get
;
set
; }
double
Y {
get
;
set
; }
double
Angle {
get
;
set
; }
#endregion
}
}
控件行为接口
IInputSupport
namespace
TouchFirst.ControlsLib.External
{
public
interface
IInputSupport
{
///
<summary>
///
注册UI的事件
///
</summary>
///
<param name="control">
承载图片的Canvas容器
</param>
void
Register(UIElement control, Canvas OutterContainer);
///
<summary>
///
增加图片路径
///
</summary>
///
<param name="path">
图片路径
</param>
void
AddImage(
string
path);
}
}
控件行为对传统输入设备的实现
TraditionalInputSupport
namespace
TouchFirst.ControlsLib.External
{
public
class
TraditionalInputSupport : IInputSupport
{
#region
Fields
private
UIElement _control;
private
Point _prevLocation;
private
ImageDecorator _image;
private
Canvas _outterContainer;
#endregion
#region
IInputSupport 成员
public
void
Register(System.Windows.UIElement control, Canvas outterContainer)
{
_control
=
control;
_outterContainer
=
outterContainer;
control.MouseLeftButtonDown
+=
MouseLeftButtonDownHandler;
control.MouseMove
+=
MouseMoveHandler;
control.MouseLeftButtonUp
+=
MouseLeftButtonUpHandler;
control.MouseWheel
+=
MouseWheelHandler;
}
public
void
AddImage(
string
filePath)
{
ImageDecorator image
=
new
ImageDecorator() { ImagePath
=
new
BitmapImage(
new
Uri(filePath)) };
//
RandomPropertyGenerator.Configure(image);
image.SetValue(Canvas.LeftProperty,
1.0
);
image.SetValue(Canvas.TopProperty,
1.0
);
_outterContainer.Children.Add(image);
}
#endregion
#region
Event Handler
private
void
MouseLeftButtonDownHandler(
object
sender, MouseButtonEventArgs args)
{
_prevLocation
=
args.GetPosition(_control);
_image
=
findImage();
takeItFront(_image);
}
private
void
MouseMoveHandler(
object
sender, MouseEventArgs args)
{
if
(args.LeftButton
==
MouseButtonState.Released
||
_image
==
null
)
return
;
Point currentLocation
=
args.GetPosition(_control);
double
offsetX
=
currentLocation.X
-
_prevLocation.X;
double
offsetY
=
currentLocation.Y
-
_prevLocation.Y;
double
prevX
=
(
double
)_image.GetValue(Canvas.LeftProperty);
double
prevY
=
(
double
)_image.GetValue(Canvas.TopProperty);
_image.SetValue(Canvas.LeftProperty, prevX
+
offsetX);
_image.SetValue(Canvas.TopProperty, prevY
+
offsetY);
_prevLocation
=
currentLocation;
Console.WriteLine(
"
{0}, {1}
"
, prevX, prevY);
}
private
void
MouseLeftButtonUpHandler(
object
sender, MouseButtonEventArgs args)
{
if
(_image
!=
null
)
{
//
takeItBehind(_image);
_image
=
null
;
}
}
private
void
MouseWheelHandler(
object
sender, MouseWheelEventArgs args)
{
Point location
=
args.GetPosition(_control);
ImageDecorator image
=
findImage();
if
(image
==
null
)
return
;
takeItFront(image);
double
scalingFactor
=
1
+
args.Delta
/
1000.0
;
image.ScaleX
*=
scalingFactor;
image.ScaleY
*=
scalingFactor;
}
private
ImageDecorator findImage()
{
var list
=
_outterContainer.Children;
foreach
(var elmt
in
list)
{
var uiElmt
=
elmt
as
ImageDecorator;
if
(uiElmt
==
null
)
continue
;
if
(uiElmt.IsMouseOver)
{
return
uiElmt;
}
}
return
null
;
}
private
void
takeItFront(UIElement uiElmt)
{
foreach
(var elmt
in
_outterContainer.Children)
{
var uiElmt2
=
elmt
as
UIElement;
if
(uiElmt2
!=
null
)
{
takeItBehind(uiElmt2);
}
}
uiElmt.SetValue(Canvas.ZIndexProperty,
99
);
}
private
void
takeItBehind(UIElement uiElmt)
{
uiElmt.SetValue(Canvas.ZIndexProperty,
1
);
}
#endregion
}
}
源码放到SkyDrive上了
http://public.blu.livefilestore.com/y1pdolMU6PHGnZitRCJtTlxRH_3_p0HyAv1zgJ2SM0-SqIrb37oC1_S_Qcixp_zl6y8Z8lCG5-nYGpipZOHgSvW2w/TouchFirst.rar?download
在下一篇会讨论如何修改这个程序以支持使用触控、手势操作(不过我这里也没有那种触控设备,所以只能勉强纸上谈兵)。