|
5. 更改以下事件处理程序的签名和代码:
注意:此事件处理程序的签名已经更改。我们使用StylusEventArgs 代替与鼠标相关的事件参数。
(代码片段 – MultiTouch – StylusEventHandlers CSharp)
public void ProcessDown(object sender, StylusEventArgs args)
{
_prevLocation = args.GetPosition(_canvas);
_picture = FindPicture(_prevLocation);
BringPictureToFront(_picture);
}
public void ProcessMove(object sender, StylusEventArgs args)
{
if (_picture == null)
return;
Point newLocation = args.GetPosition(_canvas);
_picture.X += newLocation.X - _prevLocation.X;
_picture.Y += newLocation.Y - _prevLocation.Y;
_prevLocation = newLocation;
}
public void ProcessUp(object sender, StylusEventArgs args)
{
_picture = null;
}
6. 注册触笔事件。
public MainWindow()
{
...
//注册(触摸)事件
StylusDown += ProcessDown;
StylusUp += ProcessUp;
StylusMove += ProcessMove;
}
7. 编译并运行。使用手指代替鼠标!
注意: 如果尝试使用多个手指会发生什么情况?为什么?
同时处理多张图片
在本任务中,我们将添加多点触摸支持。触摸屏幕的每个手指都会获得一个唯一的触摸 ID。只要这根手指继续触摸屏幕,系统就会将相同的触摸 ID 与该手指关联。当手指离开屏幕表面时,该触摸 ID 将被系统释放并可被硬件再次使用。在我们的示例中,当一根手指触摸图片时,应该将该手指的唯一触摸 ID 与该图片关联,直到该手指离开屏幕。如果两个或更多手指同时触摸屏幕,那么每个手指都可以操作相关的图片。
当使用 Stylus 事件作为触摸事件时,可以从 Stylus 事件参数中提取出触摸 ID:args.StylusDevice.Id
WPF 将使用相关的 StylusDevice.Id(触摸 ID)不断为每个触摸屏幕的手指触发事件。
1. 我们需要同时跟踪多张图片。对于每张图片,触摸 ID、上一个位置与图片用户控件之间必须保持关联。我们将首先添加一个新的 PictureTracker 类:
注意:PictureTracker 类也在 %TrainingKitInstallDir%\MultiTouch\Assets\PictureHandling下以实验资源的形式提供,请选择您想要使用的语言(C#)。
class PictureTracker
{
private Point _prevLocation;
public Picture Picture { get; set; }
public void ProcessDown(Point location)
{
_prevLocation = location;
}
public void ProcessMove(Point location)
{
Picture.X += location.X - _prevLocation.X;
Picture.Y += location.Y - _prevLocation.Y;
_prevLocation = location;
}
public void ProcessUp(Point location)
{
//什么都不做,可能有另一个触摸ID仍下跌
}
}
2. 现在我们需要一个词典,以将活动的触摸 ID 映射到相应的 PictureTracker 实例。我们将创建一个 PictureTrackerManager 类来包含该词典并处理各种触摸事件。无论何时触发了触摸事件,PictureTrackerManager 都将尝试找到关联的 PictureTracker 实例并要求它处理该触摸事件。换言之,PictureTrackerManager 将获得触摸事件。它寻找作为实际事件目标的 PictureTracker 实例并将触摸事件分派给它。现在的问题是如何找到正确的 PictureTracker 实例。我们需要考虑一些不同的场景:
a. 发生 ProcessDown 事件时,有 3 种选择:
i. 手指触摸一个空位置。不会发生任何事件。
ii. 手指触摸新图片。必须创建一个新 PictureTracker 实例,必须在触摸 ID 映射中创建一个新条目。
iii. 第 2 个(或更多)手指触摸已经被跟踪的图片。我们必须将新的触摸 ID 与相同的 PictureTracker 实例相关联。
b. 发生 ProcessMove 事件时,有 2 种选择:
i. 手指的触摸 ID 未与一个 PictureTracker 相关联。不应该发生任何事件。
ii. 手指的触摸 ID 与一个 PictureTracker 关联。我们需要将事件转发给它。
c. 发生 ProcessUp 事件时,有 2 种选择:
i. 删除了一个手指触摸 ID,但是至少还存在一个相关的触摸 ID。我们需要从映射中删除此条目。
ii. 删除了最后一个相关的触摸 ID。我们需要从映射中删除该条目。图片跟踪器不再使用并且会被当作垃圾收集走。
3. 通过分析这些情形,我们可以定义 PictureTrackerManager 的设计条件:
a. 它必须拥有一个映射:触摸 ID PictureTracker
private readonly Dictionary<int, PictureTracker> _pictureTrackerMap
4. 添加以下 PictureTrackerManager 类:
注意:PictureTrackerManager 类也以实验资产的形式在 %TrainingKitInstallDir%\MultiTouch\Assets\PictureHandling 下提供,
class PictureTrackerManager
{
//图片之间的接触和ID跟踪
private readonly Dictionary<int, PictureTracker> _pictureTrackerMap = new Dictionary<int, PictureTracker>();
private readonly Canvas _canvas;
public PictureTrackerManager(Canvas canvas)
{
_canvas = canvas;
}
public void ProcessDown(object sender, StylusEventArgs args)
{
Point location = args.GetPosition(_canvas);
PictureTracker pictureTracker = GetPictureTracker(args.StylusDevice.Id, location);
if (pictureTracker == null)
return;
pictureTracker.ProcessDown(location);
}
public void ProcessUp(object sender, StylusEventArgs args)
{
Point location = args.GetPosition(_canvas);
PictureTracker pictureTracker = GetPictureTracker(args.StylusDevice.Id);
if (pictureTracker == null)
return;
pictureTracker.ProcessUp(location);
_pictureTrackerMap.Remove(args.StylusDevice.Id);
}
public void ProcessMove(object sender, StylusEventArgs args)
{
PictureTracker pictureTracker = GetPictureTracker(args.StylusDevice.Id);
if (pictureTracker == null)
return;
Point location = args.GetPosition(_canvas);
pictureTracker.ProcessMove(location);
}
private PictureTracker GetPictureTracker(int touchId)
{
PictureTracker pictureTracker = null;
_pictureTrackerMap.TryGetValue(touchId, out pictureTracker);
return pictureTracker;
}
private PictureTracker GetPictureTracker(int touchId, Point location)
{
PictureTracker pictureTracker;
//我们已经根据笔触ID追踪到了图片
if (_pictureTrackerMap.TryGetValue(touchId, out pictureTracker))
return pictureTracker;
//获取图片下的触摸位置
Picture picture = FindPicture(location);
if (picture == null)
return null;
//我们根据其他ID来追踪图片
pictureTracker = (from KeyValuePair<int, PictureTracker> entry in _pictureTrackerMap
where entry.Value.Picture == picture
select entry.Value).FirstOrDefault();
//第一次
if (pictureTracker == null)
{
//创建
pictureTracker = new PictureTracker();
pictureTracker.Picture = picture;
BringPictureToFront(picture);
}
//记得接触ID和图片之间的相关性实证分析
_pictureTrackerMap[touchId] = pictureTracker;
return pictureTracker;
}
/// <summary>
/// 在触摸位置中找到图片
/// </summary>
/// <param name="pointF">触摸位置</param>
/// <returns>空的图片或照片,如果没有在触摸位置存在</returns>
private Picture FindPicture(Point location)
{
HitTestResult result = VisualTreeHelper.HitTest(_canvas, location);
if (result == null)
return null;
Image image = result.VisualHit as Image;
if (image == null)
return null;
return image.Parent as Picture;
}
private void BringPictureToFront(Picture picture)
{
if (picture == null)
return;
var children = (from UIElement child in _canvas.Children
where child != picture
orderby Canvas.GetZIndex(child)
select child).ToArray();
for (int i = 0; i < children.Length; ++i)
{
Canvas.SetZIndex(children[i], i);
}
Canvas.SetZIndex(picture, children.Length);
}
}
5. 将以下字段声明添加到 MainWindow 类的开头:
private readonly PictureTrackerManager _pictureTrackerManager;
private readonly PictureTrackerManager _pictureTrackerManager;
6. 修改 MainWindow 构造函数:
a. 在调用 InitializeComponent() 之后,添加管理器初始化:
_pictureTrackerManager = new PictureTrackerManager(_canvas);
_pictureTrackerManager = new PictureTrackerManager(_canvas);
b. 更改触笔事件注册代码
//Register for stylus (touch) events
StylusDown += _pictureTrackerManager.ProcessDown;
StylusUp += _pictureTrackerManager.ProcessUp;
StylusMove += _pictureTrackerManager.ProcessMove;
7. 从 MainWindow 类删除 ProcessDown、ProcessMove 和 ProcessUp 事件处理程序。这里将不再需要它们,因为它们现在已包含在 PictureTrackerManager 类中。
8. 编译并运行。尝试同时抓取多张图片。尝试使用多个手指抓取一张图片。发生了什么情况?为什么?
<本内容未完待续...> (责任编辑:admin) |