C# UWP:基于ScrollViewer计算变换
我有一个windows通用应用程序,其中我正在使用DirectX渲染场景。我想使用Scrollviewer,因此我在Scrollviewer后面渲染我的场景,并希望基于Scrollviewer计算场景变换。到目前为止,它运行良好,尤其是在翻译和滚动方面。但当我放大时,场景会在两种特殊情况下跳跃:C# UWP:基于ScrollViewer计算变换,c#,xaml,windows-10,uwp,win2d,C#,Xaml,Windows 10,Uwp,Win2d,我有一个windows通用应用程序,其中我正在使用DirectX渲染场景。我想使用Scrollviewer,因此我在Scrollviewer后面渲染我的场景,并希望基于Scrollviewer计算场景变换。到目前为止,它运行良好,尤其是在翻译和滚动方面。但当我放大时,场景会在两种特殊情况下跳跃: 场景有足够的空间,并且居中,现在需要滚动 相反的方向 我或多或少使用了以下代码: float zoom = scrollViewer.ZoomFactor; float inverseZoom = 1
float zoom = scrollViewer.ZoomFactor;
float inverseZoom = 1f / scrollViewer.ZoomFactor;
float scaledContentW = Document.Size.X * scrollViewer.ZoomFactor;
float scaledContentH = Document.Size.Y * scrollViewer.ZoomFactor;
float translateX;
float translateY;
if (scaledContentW < scrollViewer.ViewportWidth)
{
translateX = ((float)scrollViewer.ViewportWidth * inverseZoom - Document.Size.X) * 0.5f;
}
else
{
translateX = -inverseZoom * (float)scrollViewer.HorizontalOffset;
}
if (scaledContentH < scrollViewer.ViewportHeight)
{
translateY = ((float)scrollViewer.ViewportHeight * inverseZoom - Document.Size.Y) * 0.5f;
}
else
{
translateY = -inverseZoom * (float)scrollViewer.VerticalOffset;
}
float visibleX = inverseZoom * (float)scrollViewer.HorizontalOffset;
float visibleY = inverseZoom * (float)scrollViewer.VerticalOffset; ;
float visibleW = Math.Min(Document.Size.X, inverseZoom * (float)scrollViewer.ViewportWidth);
float visibleH = Math.Min(Document.Size.Y, inverseZoom * (float)scrollViewer.ViewportHeight);
Rect2 visibleRect = new Rect2(visibleX, visibleY, visibleW, visibleH);
transform =
Matrix3x2.CreateTranslation(
translateX,
translateY) *
Matrix3x2.CreateScale(zoom);
float zoom=scrollViewer.ZoomFactor;
float inverseZoom=1f/scrollViewer.ZoomFactor;
float scaledContentW=Document.Size.X*scrollViewer.ZoomFactor;
float scaledContentH=Document.Size.Y*scrollViewer.ZoomFactor;
浮动translateX;
浮动平移;
if(scaledContentW
您可以在此处获得一个示例:
为了确保我的眼睛没有被打断,我在放大,并将平移和缩放值写入了一个文件。你可以在这里看到:
各列的含义如下:
第1列:变换矩阵的计算缩放值(M11)=ScrollViewer.ZoomFactor
第2列:矩阵的计算x偏移量(见上文)
第3列:矩阵*向量(500500)结果的x值,此处:Column 1*500+Column 2
你看,矩阵值看起来不错,但是当应用转换时,你会在几毫秒内得到向右的小跳跃。一种理论是,由于滚动条变得可见,视口可能会发生变化。但事实并非如此。我还在这里尝试了固定值,使滚动条可见,甚至为scrollviewer创建了一个完全没有滚动条的自定义模板
顺便说一句:这是一篇交叉文章,我在这里也问了一个问题:你看到了这种行为,因为当你缩放的大小大于ScrollViewer的大小时,缩放的中心点会移动。要解决此问题,只需订阅
ScrollViewer
的LayoutUpdate
事件,并在处理程序中手动将其内容保留在中心
private void ScrollViewer_LayoutUpdated(object sender, object e)
{
this.ScrollViewer.ChangeView(this.ScrollViewer.ScrollableWidth / 2, this.ScrollViewer.ScrollableHeight / 2, this.ScrollViewer.ZoomFactor, true);
}
这将修复Win2D中两个抽屉的矩形
s上的跳跃运动
更新 为了证明我的观点,这种跳跃行为最有可能是由于内容大小超过滚动查看器的大小时,出现异常的translate x和/或y值变化。因此,我编写了一些代码,将这些值记录在屏幕上,如下所示-
...
this.Test1.Text += ((float)translateX).ToString() + " ";
this.Test2.Text += ((float)translateY).ToString() + " ";
session.Transform =
Matrix3x2.CreateTranslation(
(float)translateX,
(float)translateY) *
Matrix3x2.CreateScale((float)zoom);
现在看上图中的数字。我所做的就是试着放大,直到惊险的场景发生。是否查看高亮显示的“平移y”值?它略高于其先前的值,这与下降趋势相反
因此,要解决此问题,您需要能够跳过这些由
ScrollViewer
引起的异常值。使用这种方法,平移不再起作用,您无法缩放到鼠标位置。@SebastianStehle如果要平移,则仅当发生缩放时才执行ChangeView;如果要缩放到鼠标位置,则获取鼠标点并根据鼠标点位置替换ChangeView的前两个参数。我不明白,为什么要手动缩放?我不想实现自定义滚动。我想使用scrollviewer的默认行为,并在它下面转换一个层。除了从“if”切换到“else”时向右(或向上)跳转一次之外,这项功能还可以正常工作,如下所述:我已经解释过了。。。这是ScrollViewer的本质。当内容变得比自身更大时,其中心点将稍微移动。如何解决这个问题?请看我答案的最后一段。你的计算是正确的。否则它甚至不会工作。在sv内放置一个xaml矩形并缩放它。你会看到它也跳了一点。因为中心点并不总是sv的中间。所以你的第二个点几乎是正确的,除了sv的值没有错,只是在一些情况下由于中心点的变化而稍微偏离。