WPF4 ベータ2におけるマニピュレーションピボットについて


前回は WPF4 ベータ2のマニピュレーションを説明しました。今回は、マニピュレーションピボットを説明します。前回のマニピュレーションを実際に作成して試した方には理解できますが、ジェスチャー操作した場合のオブジェクトの動きは、ジェスチャー動作の中心点からの移動量がManipulationDeltaイベントで処理しています。このため操作対象のオブジェクトに対する中心点に対しての操作とは限らないのです。これに対して操作対象オブジェクトのある点を中心(たとえば中心点など)にマニピュレーション操作を行いたい場合に利用するのが、ManipulationPivotオブジェクトになります。具体的にどうするかといえば、前回のXAMLに対するコードを以下のように記述します。

private void canvas_ManipulationStarting(object sender,
ManipulationStartingEventArgs e)
{
// コンテナの設定
e.ManipulationContainer = canvas;
// ピボットの初期化
e.Pivot = GetCenterPivot(e.OriginalSource);

e.Handled = true;
}

// ManipulationPivotを取得します
private ManipulationPivot GetCenterPivot(object o)
{
var element = (UIElement)o;
var elementBounds = element.RenderTransform.TransformBounds(
VisualTreeHelper.GetDrawing(element).Bounds);
// 中心位置を設定したピボット
Point center = new Point(
(elementBounds.Left + elementBounds.Right) / 2,
(elementBounds.Top + elementBounds.Bottom) / 2);
ManipulationPivot pivot = new ManipulationPivot(center, 48);

return pivot;
}



ManipulationStartingイベントハンドラで、ManipulationPivotのインスタンスを設定します。上記のコードでは、GetCenterPivotメソッドで対象オブジェクトの中心座標を持つManipulationPivotのインスタンスを作成しています。このコードで注目して欲しい個所は、elemengtBoundsを取得しているコードです。このコードの行っていることは、以下の通りです。



  • VisualTreeHelper.GetDrawingメソッドを使って描画されている UI要素の描画コンテンツ(DrawingGroup)を取得して、Boundsプロパティによって軸平行境界(X軸とY軸に対して描画コンテンツを包含する長方形とでも考えれば良いでしょう)を取得します。

  • UIElement.RenderTransform.TransformBoundsメソッドによって、軸並行境界を変換して指定した境界が収まる軸並行境界ボックス(軸に対して平行な長方形のこと)を取得します。

  • 取得した長方形の中心点を持つ、ManipulationPivotのインスタンスを作成します。

上記のような処理は、対象オブジェクトの描画範囲や境界を判断するのによく使う方法になります。次にManipulationDeltaイベントハンドラに記述するコードを以下に示します。

private void canvas_ManipulationDelta(object sender,
ManipulationDeltaEventArgs e)
{
// 操作対象のUI要素を取得
var element = e.OriginalSource as UIElement;
// 移動させるために MatrixTransformを取得
var transform = element.RenderTransform as MatrixTransform;
// 取得したMatrixTransformよりMatrixを取得します
// (移動させるためのMatrixTransformを作成するためです)
var matrix = transform == null ?
Matrix.Identity : transform.Matrix;
// 移動量を設定します
// (ScaleAt:ズーム、RotateAt:回転、TranslateAt:移動)
matrix.ScaleAt(e.DeltaManipulation.Scale.X,
e.DeltaManipulation.Scale.Y,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);
matrix.RotateAt(e.DeltaManipulation.Rotation,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);
matrix.Translate(e.DeltaManipulation.Translation.X,
e.DeltaManipulation.Translation.Y);
// 移動します
element.RenderTransform = new MatrixTransform(matrix);
// ピボットの更新
if (!e.IsInertial)
Manipulation.SetManipulationPivot(
element, GetCenterPivot(element));
}

上記のコードのマニピュレーションとしてのコードは前回と同じです。異なるのは、最後にピボットを更新するコードが追加されている点です。このコードは「if (!e.IsInertial)」というif文で記述しています。このif文は、IsInertialというプロパティから理解できるようにイナーシア操作で無いという意味になります。この意味は、イナーシアの説明を行う時にしますので、マニピュレーションピボットでは必要になるものだと理解すれば良いでしょう。このif文で行っているのは、マニピュレーション操作で移動したオブジェクトを使って新しく中心点を持つManipulationPivotのインスタンスを設定しなおしているということです。このようにすることで、マニピュレーション操作が対象オブジェクトの中心点で行われるようになります。 

PS. IsInertialプロパティから予測できるようにWPF4では、ManipulationとInertiaが統合されています。Manipulationであれ、Inertiaであれ、操作するためのイベントハンドラがManipulationDeltaイベントになっています。このためManipulationかInertiaかによって、記述すべきコードを分離するためにIsInertialプロパティがあります。

Comments (0)

Skip to main content