C# 我怎样才能避免一个“错误”;“跳跃”;在画布上缩放时,当缩放中心因metro风格应用程序中的挤压(缩放)或其他手势而改变时

C# 我怎样才能避免一个“错误”;“跳跃”;在画布上缩放时,当缩放中心因metro风格应用程序中的挤压(缩放)或其他手势而改变时,c#,microsoft-metro,windows-runtime,C#,Microsoft Metro,Windows Runtime,在metro风格的应用程序中,当缩放中心因挤压(缩放)或其他手势而改变时,如何避免在画布对象上缩放时发生“跳跃” 我试图存档的行为类似于预装的win8 maps应用程序的缩放行为。如果执行挤压手势(放大或缩小),缩放中心将设置在手指之间的中间位置。如果抬起其中一个手指,将其放在另一个点上,则可以立即执行另一个缩放操作,缩放中心将正确更改,而无任何跳跃(画布中对象的UI坐标的跳跃) 我正在尝试使用复合变换在大型画布对象(在C#WinRT应用程序中)上实现类似的行为。我想允许平移和缩放,不允许旋转(

在metro风格的应用程序中,当缩放中心因挤压(缩放)或其他手势而改变时,如何避免在画布对象上缩放时发生“跳跃”

我试图存档的行为类似于预装的win8 maps应用程序的缩放行为。如果执行挤压手势(放大或缩小),缩放中心将设置在手指之间的中间位置。如果抬起其中一个手指,将其放在另一个点上,则可以立即执行另一个缩放操作,缩放中心将正确更改,而无任何跳跃(画布中对象的UI坐标的跳跃)

我正在尝试使用复合变换在大型画布对象(在C#WinRT应用程序中)上实现类似的行为。我想允许平移和缩放,不允许旋转(现在,也许我以后会添加它):

我这样初始化,将缩放中心放置在屏幕中心:

this.compositeTransform = new CompositeTransform();
this.compositeTransform.CenterX = this.mainPage.Width / 2.0;
this.compositeTransform.CenterY = this.mainPage.Height / 2.0;

this.innerCanvas.RenderTransform = compositeTransform;
然后我将使用操纵增量事件来获取输入数据

private void InnerCanvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{                        
    this.compositeTransform.ScaleX *= e.Delta.Scale;
    this.compositeTransform.ScaleY *= e.Delta.Scale;

    this.compositeTransform.CenterX = e.Position.X;
    this.compositeTransform.CenterY = e.Position.Y;

    this.compositeTransform.TranslateX += e.Delta.Translation.X;
    this.compositeTransform.TranslateY += e.Delta.Translation.Y;                      
}
只要我做同样的手势,这就可以正常工作。当我做挤压动作时,新中心的计算是正确的。但是,更改缩放中心会导致突然跳跃,例如,在捏手势后抬起一根手指时。当然,我只能为捏的姿势改变中心,但跳跃的问题仍然存在。这当然是合乎逻辑的,因为缩放与新的缩放中心一起工作。我还没有想出一个办法,如何避免跳跃。由于比例值本身保持不变,因此必须能够在改变中心的情况下具有相同的外观(坐标不变)

我目前的推理是,我必须以某种方式更改TranslateX和TranslateY坐标,以便在某种程度上平衡新的中心点,即ui元素的当前屏幕坐标保持不变。类似这样的内容(scaleTransform是scaleTransform,它只获取缩放数据)


但这也不行。整个问题似乎是平板电脑上的一个标准问题,但我没有找到解决方案,尽管搜索过多,可能我使用了错误的关键字。

我建议查看示例


已经为您实现了缩放,只需在打开缩放的情况下使用滚动查看器即可。这是否符合您的要求?

我终于想出了如何通过手动转换而不是使用ScrollViewer来解决这个问题

    TranslateTransform tmpTranslate = new TranslateTransform();

    private void InnerCanvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
    {                                       
        //Transform world space into local space (origin: Scale center from the last manipulation event)            

        this.tmpTranslate.X = this.compositeTransform.CenterX;
        this.tmpTranslate.Y = this.compositeTransform.CenterY;

        Point center = this.compositeTransform.Inverse.TransformPoint(e.Position);

        Point localPoint = tmpTranslate.Inverse.TransformPoint(center);                        

        //Now scale the point in local space

        localPoint.X *= this.compositeTransform.ScaleX;
        localPoint.Y *= this.compositeTransform.ScaleY;

        //Transform local space into world space again
        Point worldPoint = tmpTranslate.TransformPoint(localPoint);

        //Take the actual scaling...
        Point distance = new Point(
            worldPoint.X - center.X,
            worldPoint.Y - center.Y);

        //...amd balance the jump of the changed scaling origin by changing the translation            

        this.compositeTransform.TranslateX += distance.X;
        this.compositeTransform.TranslateY += distance.Y;

        //Also set the scaling values themselves, especially set the new scale center...

        this.compositeTransform.ScaleX *= e.Delta.Scale;
        this.compositeTransform.ScaleY *= e.Delta.Scale;            

        this.compositeTransform.CenterX = center.X;
        this.compositeTransform.CenterY = center.Y;

        //And consider a translational shift

        this.compositeTransform.TranslateX += e.Delta.Translation.X;
        this.compositeTransform.TranslateY += e.Delta.Translation.Y;                                    
    }
如果我们加上

distance.x = (currentcenter.x - previouscenter.x) * (scalefactortillnow - 1)
同样地

distance.y = (currentcenter.y - previouscenter.y) * (scalefactortillnow - 1)

这样就足以补偿因中心变化而产生的跳跃。
我亲自面对这个问题,发现这个方法很有效。

嗨,罗斯,谢谢!将画布放入滚动查看器可以解决“跳跃”行为的问题。但是,我现在必须在添加新内容时动态调整画布的大小方面做一些工作,也许找到一些“自己转换”方法的解决方案会更好,但我想我可以接受。如果您有一些定义大小的内容,滚动查看器可以非常好地工作。如果你想扩展到任意维度,转换方法更适合我的竞争对手。对不起,罗斯,我必须取消勾选你的答案,尽管我已经为许多可能的类似问题找到了解决方案。即使我试图补偿这个跳跃动作,但我忽略了局部空间中的缩放部分。非常感谢塞巴斯蒂安
distance.y = (currentcenter.y - previouscenter.y) * (scalefactortillnow - 1)
composite.translatex += distance.x; 
composite.translatey += distance.y;