我有一个必须响应TouchUp事件的UserControl,它位于Viewbox中,需要通过捏合操作进行平移和缩放。控件上的触摸事件处理得很好。但是,如果两个夹点完全包含在用户控件或其周围的视口空间内,则夹点操作仅缩放ViewPort。如果夹点横跨用户控制边界,则ManipulationDelta会丢失其中一个点并报告(1,1)的比例。
如果从处理TouchUp事件的控件中删除IsManipulationEnabled =“True”,则缩放有效,但触摸事件不会触发。
在处理用户控件中的触摸事件的同时,我可以做什么来保持ViewPort中的操作?
<Window x:Class="TouchTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Touch Test"
Height="400"
Width="700"
ManipulationDelta="OnManipulationDelta"
ManipulationStarting="OnManipulationStarting">
<Grid Background="Transparent"
IsManipulationEnabled="True">
<Viewbox x:Name="Viewbox"
Stretch="Uniform">
<Viewbox.RenderTransform>
<MatrixTransform/>
</Viewbox.RenderTransform>
<Grid Width="800"
Height="800"
Background="LightGreen"
IsManipulationEnabled="True"
TouchUp="OnTouchUp">
<TextBlock x:Name="TimeTextBlock"
FontSize="100"
TextAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Viewbox>
<TextBlock x:Name="ScaleTextBlock"
FontSize="10"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"/>
</Grid>
</Window>
代码隐藏中的处理程序:
private void OnTouchUp(object sender, TouchEventArgs e)
{
TimeTextBlock.Text = DateTime.Now.ToString("H:mm:ss.fff");
}
private void OnManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
e.ManipulationContainer = this;
}
private void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
if (Viewbox == null)
{
return;
}
ManipulationDelta delta = e.DeltaManipulation;
ScaleTextBlock.Text = $"Delta Scale: {delta.Scale}";
MatrixTransform transform = Viewbox.RenderTransform as MatrixTransform;
if (transform == null)
{
return;
}
Matrix matrix = transform.Matrix;
Point position = ((FrameworkElement)e.ManipulationContainer).TranslatePoint(e.ManipulationOrigin, Viewbox);
position = matrix.Transform(position);
matrix = MatrixTransformations.ScaleAtPoint(matrix, delta.Scale.X, delta.Scale.Y, position);
matrix = MatrixTransformations.PreventNegativeScaling(matrix);
matrix = MatrixTransformations.Translate(matrix, delta.Translation);
matrix = MatrixTransformations.ConstrainOffset(Viewbox.RenderSize, matrix);
transform.Matrix = matrix;
}
支持班:
public static class MatrixTransformations
{
/// <summary>
/// Prevent the transformation from being offset beyond the given size rectangle.
/// </summary>
/// <param name="size"></param>
/// <param name="matrix"></param>
/// <returns></returns>
public static Matrix ConstrainOffset(Size size, Matrix matrix)
{
double distanceBetweenViewRightEdgeAndActualWindowRight = size.Width * matrix.M11 - size.Width + matrix.OffsetX;
double distanceBetweenViewBottomEdgeAndActualWindowBottom = size.Height * matrix.M22 - size.Height + matrix.OffsetY;
if (distanceBetweenViewRightEdgeAndActualWindowRight < 0)
{
// Moved in the x-axis too far left. Snap back to limit
matrix.OffsetX -= distanceBetweenViewRightEdgeAndActualWindowRight;
}
if (distanceBetweenViewBottomEdgeAndActualWindowBottom < 0)
{
// Moved in the x-axis too far left. Snap back to limit
matrix.OffsetY -= distanceBetweenViewBottomEdgeAndActualWindowBottom;
}
// Prevent positive offset
matrix.OffsetX = Math.Min(0.0, matrix.OffsetX);
matrix.OffsetY = Math.Min(0.0, matrix.OffsetY);
return matrix;
}
/// <summary>
/// Prevent the transformation from performing a negative scale.
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
public static Matrix PreventNegativeScaling(Matrix matrix)
{
matrix.M11 = Math.Max(1.0, matrix.M11);
matrix.M22 = Math.Max(1.0, matrix.M22);
return matrix;
}
/// <summary>
/// Translate the matrix by the given vector to providing panning.
/// </summary>
/// <param name="matrix"></param>
/// <param name="vector"></param>
/// <returns></returns>
public static Matrix Translate(Matrix matrix, Vector vector)
{
matrix.Translate(vector.X, vector.Y);
return matrix;
}
/// <summary>
/// Scale the matrix by the given X/Y factors centered at the given point.
/// </summary>
/// <param name="matrix"></param>
/// <param name="scaleX"></param>
/// <param name="scaleY"></param>
/// <param name="point"></param>
/// <returns></returns>
public static Matrix ScaleAtPoint(Matrix matrix, double scaleX, double scaleY, Point point)
{
matrix.ScaleAt(scaleX, scaleY, point.X, point.Y);
return matrix;
}
}
答案 0 :(得分:1)
所以,我不是一个wpf程序员。但是有一个可能适合你的建议/解决方法。
你可以按如下方式对事物进行编码:
设置IsManipulationEnabled =&#34; True&#34; (在这种情况下,OnGouchUp不会被LightGreen中的网格触发)
将OnTouchUp
设置为Viewbox x:Name="Viewbox"
或此Grid
上方的Viewbox
(而不是800x800 Grid
)
因此,只要您触摸Viewbox中的任何位置(而不仅仅是LightGreen区域内),就会触发OnTouchUp
现在触发OnTouchUp时,只需检查坐标是否位于LightGreen框的区域内。如果是 - >更新时间,如果不是,请保留时间。
我知道这是一种解决方法。仍然发布了答案,以防它可能有用。
答案 1 :(得分:0)
我不确定您发布的样本是否完全反映了您的代码......但我看到的是:您没有管理ManipulationCompleted和LostMouseCapture。你也没有制作任何MouseCapture()MouseRelease(),所以当操作向窗口输出时你松开它....在这个repo上搜索“鼠标捕获”,你会看到即使没有操作事件,这是相当复杂的.. .. https://github.com/TheCamel/ArchX/search?utf8=%E2%9C%93&q=mouse+capture&type=