限制平移量以防止图像偏离窗口。

8

介绍:

我已将SVG导出为XAML,并将其转换为带有大量路径的画布。

将该画布设置为简单自动生成窗口的主要内容后,图像被剪裁,因为它比主窗口的客户区域大。

我通过实现平移来解决了这个问题。

由于我计划稍后调整缩放,因此我在Canvas的XAML中添加了虚拟的ScaleTransform,并将其RenderTransformOrigin更改为0.5, 0.5(以便我可以围绕图像中心缩放)。

当窗口加载时,我希望图像居中,因此我将该画布放在Viewbox内,经过调整几个属性后,似乎工作正常。

问题:

由于我更改了Canvas的RenderTransformOrigin,我无法弄清楚可以限制平移量的数学方法。

即使Viewbox是主窗口的内容,我也无法获取主窗口客户区域的尺寸(Viewbox会调整大小以适应其内容)。这使我的任务更加困难。

我的解决方案:

似乎没有其他方法可以获取主窗口的客户区矩形,除了使用P/InvokeGetClientRect WinAPI调用。

还有一种方法是通过查询SystemParametersInfo来获取非客户端度量,例如边框和标题栏,但这是一个可能因应用主题等原因而失败的估计值

我还没有尝试使用P/Invoke,因为我目前拒绝这样做。必须有比这更好的解决方案!这条路应该是我的最后选择,也是我纯粹出于绝望而做出的选择。

我已经尝试过自己寻找替代方法,但失败了。

我尝试使用TransformToAncestor(...).Transformtobounds(..)进行计算,但也失败了。

问题:

如何限制平移,使图像在用户拖动过多时不会从主窗口消失?

我将接受替代方案。提交的代码是一个经验不足、自学的初学者的尝试,所以我接受建设性的批评和建议。

相关信息:

为了让这篇文章尽可能简短,我只提供相关的XAML和“代码后台”片段如下。
完整代码已经粘贴在Pastebin上,并且可以在本文底部找到。
相关的XAML片段:
<Window  x:Class="TestZaMapu.MainWindow" 
        Name="GlavniProzor" 
        WindowStartupLocation="CenterScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" 
        Height="350" 
        Width="525" 
        MouseLeftButtonDown="GlavniProzor_MouseLeftButtonDown" 
        MouseLeftButtonUp="GlavniProzor_MouseLeftButtonUp" 
        MouseMove="GlavniProzor_MouseMove" 
        LostMouseCapture="GlavniProzor_LostMouseCapture">
    <Viewbox 
        Name="surface"
        Stretch="UniformToFill" 
        HorizontalAlignment="Center"
        VerticalAlignment="Center">
        <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                Background="Blue" 
                x:Name="svg4306" 
                Width="494.44705" 
                Height="510.55356"
                <!-- needed in the future, for zooming around center-->
                RenderTransformOrigin="0.5, 0.5">
            <!--Unknown tag: metadata-->
            <Canvas.RenderTransform>
                <TransformGroup>
                    <!-- I intend to experiment with scaling in the future, so I added the below part -->
                    <ScaleTransform ScaleX="1" ScaleY="1"/>
                    <!-- I have used dependency properties for translation -->
                    <TranslateTransform X="{Binding TranslationFactorX, ElementName=GlavniProzor, Mode=TwoWay}" Y="{Binding TranslationFactorY, ElementName=GlavniProzor, Mode=TwoWay}"/>
                </TransformGroup>
            </Canvas.RenderTransform>
        <!-- Bunch of Path objects, omitted for brevity-->
        </Canvas>
    </Viewbox>
</Window>

相关的代码片段:

namespace TestZaMapu
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            TranslationFactorX = 0;
            TranslationFactorY = 0;
            isPanning = false;

        }

        // panning variables
        private Point ptOldPosition;
        private bool isPanning ;

        // dependency properties for translation along X and Y axes

        public static readonly DependencyProperty TranslateX =
            DependencyProperty.Register("TranslationFactorX", typeof(double), typeof(MainWindow));

        public static readonly DependencyProperty TranslateY =
            DependencyProperty.Register("TranslationFactorY", typeof(double), typeof(MainWindow));

        public double TranslationFactorX
        {
            get { return (double)GetValue(TranslateX); }
            set { SetValue(TranslateX, value); }
        }

        public double TranslationFactorY
        {
            get { return (double)GetValue(TranslateY); }
            set { SetValue(TranslateY, value); }
        }

        // mouse event handlers for panning

        private void GlavniProzor_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            if (isPanning )
                return;
            isPanning = this.CaptureMouse(); 
            ptOldPosition = e.GetPosition(this);
        }

        private void GlavniProzor_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

            if (this.IsMouseCaptured)
            {
                this.ReleaseMouseCapture();
                isPanning = false;
            }
        }

        private void GlavniProzor_MouseMove(object sender, MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (isPanning )
            {
                Point ptNewPosition = e.GetPosition(this);

                if (ptNewPosition != ptOldPosition)
                {
                    Vector direction = ptOldPosition - ptNewPosition;

                    direction.X = TranslationFactorX - direction.X;
                    direction.Y = TranslationFactorY - direction.Y;

                    TranslationFactorX = direction.X;
                    TranslationFactorY = direction.Y;

                    ptOldPosition = ptNewPosition;
                }
            }
        }

        private void GlavniProzor_LostMouseCapture(object sender, MouseEventArgs e)
        {
            isPanning = false;
            this.OnLostMouseCapture(e);
        }
    }
}

这里是完整的XAML代码,这里是完整的“代码后台”。


为了让这篇文章尽可能地简短,现在已经有点晚了。:) 但是说真的,一个好的 Stack Overflow 问题应该包括一个好的、最小化的、完整的代码示例,清楚地说明问题,以及对手头具体问题的简明描述。你的叙述和代码中几乎肯定有很多内容不需要阅读,才能解决你需要帮助的具体问题。 - Peter Duniho
可能您所需做的只是将内容放入Grid中,然后再将其包含在ScrollViewer中。但是由于问题表述过于广泛,无法确定。 - Peter Duniho
1
@PeterDuniho:我不明白我的帖子有什么不清楚/广泛的地方。我已经从SVG导出了图像到XAML(这是一个巨大的画布)。我想在简单的窗口内显示该图像。它无法适应,所以我决定实现平移。由于稍后我将添加围绕中心缩放,因此我编辑了Canvas的RenderTransformOrigin为0.5, 0.5。然后将Canvas放置在Viewbox内,而该Viewbox是主窗口的内容。我想限制平移,使图像不会移出窗口,留下空白。完整的XAML和代码在帖子底部链接。 - AlwaysLearningNewStuff
2个回答

1
听起来非常简单,但如果你的目标是防止你的向量超出分配给它的空间,为什么不将你的Viewbox的Stretch="UniformToFill"更改为Stretch="Uniform"呢?

1
我并没有完全阅读问题(我认为没有人会),但这是我在图表库中使用的代码来限制平移。这是数学计算。现在将其适应到你的情况中。提示:下次只输入相关代码,这样我们可以提供更好的答案。
当平移结束时(在我的情况下为鼠标弹起事件),我调用此方法。
如果有帮助的话,这是库(https://github.com/beto-rodriguez/Live-Charts),也许它可以帮助你查看源代码。放松点,我认为你正在把它变得比实际要困难。
    private void PreventGraphToBeVisible()
    {
        var tt = Canvas.RenderTransform as TranslateTransform;
        if (tt == null) return;
        var eX = tt.X;
        var eY = tt.Y;
        var xOverflow = -tt.X + ActualWidth - Canvas.Width;
        var yOverflow = -tt.Y + ActualHeight - Canvas.Height;

        if (eX > 0)
        {
            tt.X = 0;
        }

        if (eY > 0)
        {
            tt.Y = 0;
        }

        if (xOverflow > 0)
        {
            tt.X = tt.X + xOverflow;
        }

        if (yOverflow > 0)
        {
            tt.Y = tt.Y + yOverflow;
        }
    }

经过整夜的奋斗,我发现我的数学计算出了问题,是因为将RenderTransformOrigin移动到“0.5,0.5”,这就是罪魁祸首。我还没有测试过你的解决方案,但我已经访问了链接并简要地观看了那些图表。当你进行缩放操作时,RenderTransformOrigin似乎保持默认状态。你能否将其更改为“0.5,0.5”并确认你的答案在这种情况下也有效?我之所以这样问是因为我已经有了适用于默认RenderTransformOrigin的工作数学计算。 - AlwaysLearningNewStuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接