【问题标题】:Limit panning amount in order to prevent image from wandering off of the window限制平移量以防止图像偏离窗口
【发布时间】:2016-01-13 02:56:15
【问题描述】:

简介:

我已将SVG 导出为XAML,它变成了具有大量路径的画布。

在制作简单的自动生成窗口的 Canvas 主要内容后,图像被裁剪,因为它大于主窗口的客户矩形。

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

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

我希望在加载窗口时图像居中,所以我将 Canvas 放在 Viewbox 中,在调整了一些属性后,它似乎工作得很好。

问题:

由于我更改了画布的 RenderTransformOrigin,我无法计算出可以限制平移量的数学运算。

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

我为解决这个问题所做的努力:

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

还有另一个 hack 用于查询 SystemParametersInfo 以获取边框和标题栏等非客户端指标,但这是一个估计,可能会因应用主题和类似情况而失败。

我没有尝试使用P/Invoke,因为我现在只是拒绝这样做。必须有比这更好的解决方案!那条路应该是我最后的选择,也是我会在绝望中走的路。

我曾尝试自行寻找替代方法,但失败了。

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

问题:

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

我会接受替代解决方案。提交的代码是一个没有经验、自学成才的初学者的尝试,所以我接受建设性的批评和建议。

相关信息:

为了使这篇文章尽可能简短,我在下面只给出相关的 XAML 和“代码隐藏”sn-ps。

完整的代码粘贴在 Pastebin 上,可以在这篇文章的最底部找到。

相关XAML sn-ps:

<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>

sn-ps 背后的相关代码:

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);
        }
    }
}

Here 是完整的 XAML,here 是完整的“代码隐藏”。

【问题讨论】:

  • “为了让这篇文章尽可能简短”——太晚了。 :) 说真的,一个好的 Stack Overflow 问题将包括清楚地说明问题的a good, minimal, complete code example,以及对当前特定问题的简明描述。为了解决您需要帮助的特定问题,您的叙述以及几乎可以肯定不需要阅读的代码有很多。
  • 您可能需要做的就是将您的内容放在Grid 中,而后者又包含在ScrollViewer 中。但对于如此广泛的问题,我们无法确定。
  • @PeterDuniho:我不明白我的帖子有什么不清楚/广泛的地方。我将图像从 SVG 导出到 XAML(它是 一个巨大的 Canvas)。我想在简单的窗口中显示该图像。它不适合,所以我决定实施平移。由于稍后我将添加缩放围绕中心,因此我已将 Canvas 的 RenderTransformOrigin 编辑为 0.5 , 0.5。然后将 Canvas 放置在 Viewbox 内,该 viewbox 就是主窗口的内容。我想限制平移,因此图像不会移出窗口,将其留空。完整的 XAML 和背后的代码链接在帖子的最底部。

标签: c# wpf xaml panning


【解决方案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 的数学工作。
【解决方案2】:

这听起来很简单,但如果您的目标是阻止向量超出分配给它的空间,为什么不将 Viewbox 的 Stretch="UniformToFill" 更改为 Stretch="Uniform"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    相关资源
    最近更新 更多