通过缩放到父级来缩放以适合画布,但通过scrollviewer提供缩放

时间:2018-12-19 00:01:42

标签: c# wpf

编辑1 19/12

经过一番谷歌搜索后,我觉得可以更简洁地说明我的问题了。我想实现“缩放以适合”,其中以适当的比例因子显示比其父级更大的画布,但为用户提供了放大并查看完整尺寸图像的能力(使用滚动查看器)。我最初的实现并没有保持图像的长宽比,而是独立地对其进行处理,然后尝试使用一个滑块来管理两者。

我偶然发现this tutorial,制作了一个可滚动和可缩放的图像查看器,提供了“缩放以适合”的效果。之后,我将代码更改为以下代码。

if (CanvasWidth > CanvasHeight)
{
  ScaleX = (Math.Floor(_scrollViewer.ViewportWidth + 0.5)) / ((double)CanvasWidth);
  ScaleY = ScaleX;

  if (_scrollViewer.Height < (CanvasHeight * ScaleY) )
  {
    ScaleX = ( _scrollViewer.Height) / (CanvasHeight);
    ScaleY = ScaleX;
  }
}
else
{
   ScaleX = (Math.Floor(_scrollViewer.ViewportHeight + 0.5)) / ((double)CanvasHeight);
   ScaleY = ScaleX;

   if (_scrollViewer.Width < ( CanvasWidth * ScaleX) )
   {
      ScaleX = ((double)_scrollViewer.Width) / ((double)CanvasWidth);
      ScaleY = ScaleX;
   }
 }

此更改似乎可以很好地起作用,但是我想知道是否有人可以向我解释如何计算长宽比,并且可以将图像正确缩放到父控件?

,即“内部if语句”的重要意义是什么,以及如何确保X和Y都相应地缩放。


原始问题

我正在画布上动态生成内容(有效地创建了一个图像地图,画布上的每个孩子都可以单击),其中内容的总宽度/高度通常大于其父对象的大小。在这种情况下,我应用 ScalerTransform 将图像缩放到合适的大小,以便在父控件中完全可见。

<Canvas.LayoutTransform>
 <ScaleTransform ScaleX="{Binding ScaleX,RelativeSource={RelativeSource 
 TemplatedParent}}" ScaleY="{Binding ScaleY,RelativeSource={RelativeSource 
 TemplatedParent}}" />
</Canvas.LayoutTransform>

“画布”上的每个子元素都有固定的宽度/高度,这意味着我可以计算出所需的内容大小。

我通过执行类似的操作来计算初始X / Y比例因子。

 ScaleX = ActualCanvasWidth / DesiredCanvasWidth;
 ScaleY = ActualCanvasHeight / DesiredCanvasHeight;

这可以按预期工作,并且可以使画布很好地适合父容器。

我的问题是我想让用户能够缩放和平移图像。为此,我将Canvas包装在ScrollViewer中并添加了Slider。

<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" x:Name="PART_ScrollViewer" VerticalScrollBarVisibility="Auto">
<Canvas x:Name="PART_MiniMapCanvas">
    <Canvas.LayoutTransform>
        <ScaleTransform ScaleX="{Binding ScaleX,RelativeSource={RelativeSource TemplatedParent}}"
                        ScaleY="{Binding ScaleY,RelativeSource={RelativeSource TemplatedParent}}" />
    </Canvas.LayoutTransform>
</Canvas></ScrollViewer>
 
<Slider TickFrequency="1" IsSnapToTickEnabled="True" Grid.Row="0" Grid.Column="0" Minimum="1" Maximum="200" Value="{Binding ScaledPercent,RelativeSource={RelativeSource TemplatedParent}}" x:Name="sliderPercent" MinWidth="100px" />

UI使用一个滑块控制缩放,其值绑定到名为 ScaledPercent 的属性。滑块的初始值是这样计算的

double scaledArea = (DesiredCanvasWidth * ScaleX) * (DesiredCanvasHeight* ScaleY);
double desiredArea = DesiredCanvasWidth * DesiredCanvasHeight;
double scaledPercent = scaledArea/desiredArea; 

据我了解,我可以执行此计算来查找整个画布的缩放比例,而不只是画布X / Y的比例因子。

您可以see here进行操作,画布及其父级的高度大约为160 * 200,所需的内容大小大约为300 * 320,相当于48000/96000,这是我使用了50%的位置通过滑块。

如果用户决定放大并将滑块的值更改为51,则将这个新的“缩放百分比”值转换为适用于画布的ScaleX / Y值。这是在依赖项属性回调中执行的

 private static void OnScaledPercentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is MiniMap map)
        {
                int newPercent = (int)e.NewValue;
                int oldPercent = (int)e.OldValue;
                int diff = newPercent - oldPercent;

                double oldWidth = map.CanvasWidth * map.ScaleX;
                double oldHeight = map.CanvasHeight * map.ScaleY;

                double scale = (diff > 0 ? (100 + diff) : (100 - Math.Abs(diff))) / 100d;

                double newHeight = scale * oldHeight;
                double newWidth = scale * oldWidth;

                map.ScaleX = newWidth / map.CanvasWidth;
                map.ScaleY = newHeight / map.CanvasHeight;
        }
    }

如您所见,我有效地将旧图像的宽度/高度缩放+/- 1%,然后计算新的缩放X / Y值。 see here似乎可以正常工作,但是如果您连续放大/缩小画布会变得很小,则无法显示。我认为这是因为我每次都在计算一个新的宽度/高度,并且最终会将其舍入为0。

很显然,我的实现过于复杂,错误且错误。如果有人可以帮助我或建议我如何实现所需的功能,我将不胜感激。

0 个答案:

没有答案