TechEd 2009 での Silverlight3 を使ったピアノサンプルについて
TechEd 2009のMVPラウンジでお見せしたSilverlight 3のマルチタッチ対応のピアノのデモですが、その後の調査で作成したデモのバグのためにSilverlight3ランタイムがハングアップしたようになっていたことが判明しました。この件は、多くの方が陥りそうな気がするので自戒の意味も込めて、状況を以下に記載します。
- Silverlight3でマルチタッチを使用するには、System.Windows.Input.Touchクラスを使用します。
具体的には、「Touch.FrameReported += Touch_FrameReported」のようにイベントハンドラを登録します。イベントハンドラは、「void Touch_FrameReported(object sebder, TouchFrameEventArgs e)」というシグネチャを持ちます。 - イベントハンドラ内では、タッチポイントコレクションを取得します。
「TouchPointCollection touchPoints e.GetTouchPoints(FrameworkElement)」メソッドでタッチポイントコレクションを取得します。タッチポイントコレクションには、複数のタッチされたポイントで構成されています。 - タッチポイントコレクションからタッチポイントを取り出して処理します。
「foreach (TouchPoint tp in touchPoints)」のようにタッチポイントを列挙します。タッチポイントには、ActionプロパティとTouchDeviceプロパティなどがあります。 - Actionプロパティによってタッチ動作を識別します。
TouchAction.Down、Move、Upという列挙値とActionプロパティを比較することでタッチ動作を記述します。タッチの動作の基本は、ダウン->移動->アップ(移動が無い場合もあります)になります。 - TouchDeviceプロパティによって、タッチされた場所を識別します。
TouchDevice.Idにタッチした場所の識別子が格納されています。つまり、ダウン->移動->アップが一回のタッチ動作であれば同じ識別子になります。複数(マルチ)のタッチであれば、TouchDevice.Idが異なるので一致するId毎にActionプロパティと組み合わせてタッチ動作を記述します。言い換えると、タッチ動作がダウン->移動->アップですからダウン時にTouchDevice.Idと座標を記録して、移動やアップ時に記録されたIdを取り出してタッチ動作にするのです。 - 私のサンプルで問題があった個所は、MouseLeftButtonDownイベントとタッチイベントの両方をハンドリングしていたことでした。これで何が問題になったかというと、軽いタッチの場合はOSというかブラウザがタッチダウンをMouseLeftButtonDownイベントに変換してしまうので、タッチダウンイベントを処理できないというものでした。
if tp.Action == TouchAction.Down)
{
Path hitKey = null;
// タッチされた場所の最上位のFrameworkElementを取得
FrameworkElement hitElement =
tp.TouchDevice.DirectOver as FrameworkElement;
// これが対処したコード
while (hitElement != null)
{
if (hitElement is Path)
{ hitKey = hitElement as Path;
Breake;
}
// Visual Tree を上へたどる
hitElement = hitElement.Parent as FrameworkElement;
}
if (hitKey != null) タッチダウンの動作を記述
}
上記のwhile文が対処コードです。このサンプルでは、Pathオブジェクトにタッチした場合に動作を作り込んでいます。while文の中で「hitElement = hitElement.Parent as FrameworkElement」とすることでVisual Treeを最上位までたどりnullでwhile文を抜けます。このwhile文を入れたことで、タッチダウンがMouseLeftButtonDownイベントに変換されなくなりました。
この動作はSilverlight3のマルチタッチ対応において仕様ともとれるものです。タッチデバイスでのタッチダウンイベントは、マウスのボタンダウンイベントと同様に扱うこともできるからです。