平移和缩放,但在父容器中包含图像

Pan and zoom, but contain image inside parent container

我正在开发自己的图像查看器,想平移和缩放图像。目前使用“ZoomBorder”的修改版本来实现这一点,来自这个答案:。

存在用户可以将图像拖出 screen/parent 容器的问题,这是不受欢迎的行为。

我创建了一个示例应用程序来说明该问题,所需代码最少:

MainWindow.xaml

<Window
    x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    SizeToContent="WidthAndHeight">
    <Grid x:Name="ParentContainer">
        <Border x:Name="MainBorderImage">
            <Image
                x:Name="MainImage" 
                Source="https://w.wallhaven.cc/full/ym/wallhaven-ympqxl.jpg"
                Stretch="Fill" />
        </Border>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        private Point origin;
        private Point start;
        private ScaleTransform scaleTransform;
        private TranslateTransform translateTransform;

        private double aspectRatio;

        public MainWindow()
        {
            InitializeComponent();

            MainImage.MouseWheel += MainImage_MouseWheel;
            MainImage.MouseLeftButtonDown += MainImage_MouseLeftButtonDown;
            MainImage.MouseLeftButtonUp += MainImage_MouseLeftButtonUp;
            MainImage.MouseMove += MainImage_MouseMove;
            PreviewMouseRightButtonDown += delegate { Reset(); };

            ContentRendered += delegate {
                InitializeZoom();
                Scale_Image();
            };
            
        }

        private void Scale_Image()
        {
            double width = MainImage.Source.Width;
            double height = MainImage.Source.Height;
            double maxWidth = Math.Min(SystemParameters.PrimaryScreenWidth - 30, width);
            double maxHeight = Math.Min(SystemParameters.PrimaryScreenHeight - 30, height);

            aspectRatio = Math.Min(maxWidth / width, maxHeight / height);
            width *= aspectRatio;
            height *= aspectRatio;

            MainImage.Width = width;
            MainImage.Height = height;
        }

        private void InitializeZoom()
        {
            // Initialize transforms
            MainImage.RenderTransform = new TransformGroup
            {
                Children = new TransformCollection {
                            new ScaleTransform(),
                            new TranslateTransform()
                        }
            };

            // Set transforms to UI elements
            scaleTransform = (ScaleTransform)((TransformGroup)
                MainImage.RenderTransform).Children.First(tr => tr is ScaleTransform);

            translateTransform = (TranslateTransform)((TransformGroup)
                MainImage.RenderTransform).Children.First(tr => tr is TranslateTransform);
        }

        private void Reset()
        {
            scaleTransform.ScaleX = 1.0;
            scaleTransform.ScaleY = 1.0;

            translateTransform.X = 0.0;
            translateTransform.Y = 0.0;
        }


        private void MainImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            MainImage.ReleaseMouseCapture();
        }

        private void MainImage_MouseMove(object sender, MouseEventArgs e)
        {
            // Don't drag when full scale
            // and don't drag it if mouse not held down on image
            if (!MainImage.IsMouseCaptured || scaleTransform.ScaleX == 1)
            {
                return;
            }

            // Drag image by modifying X,Y coordinates
            var dragMousePosition = start - e.GetPosition(this);

            var newXproperty = origin.X - dragMousePosition.X;
            var newYproperty = origin.Y - dragMousePosition.Y;

            if (newXproperty < 0)
            {
                newXproperty = 0;
            }

            if (newYproperty < 0)
            {
                newYproperty = 0;
            }

            /// Top corners are 0, which is easy enough, but how to count
            /// the bottom corners?

            if (true) // Calculate to not go out of parent container
            {
                // Set max X property
            }

            if (true) // Calculate to not go out of parent container
            {
                // Set max Y property
            }

            translateTransform.X = newXproperty;
            translateTransform.Y = newYproperty;

            e.Handled = true;
        }

        private void MainImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            MainImage.CaptureMouse();
            start = e.GetPosition(MainBorderImage);
            origin = new Point(translateTransform.X, translateTransform.Y);
        }

        private void MainImage_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            double zoom = e.Delta > 0 ? .2 : -.2;
            if (!(e.Delta > 0) && (scaleTransform.ScaleX < .4 || scaleTransform.ScaleY < .4))
                return;

            Point relative = e.GetPosition(MainImage);
            double absoluteX;
            double absoluteY;

            absoluteX = relative.X * scaleTransform.ScaleX + translateTransform.X;
            absoluteY = relative.Y * scaleTransform.ScaleY + translateTransform.Y;

            scaleTransform.ScaleX += zoom;
            scaleTransform.ScaleY += zoom;

            translateTransform.X = absoluteX - relative.X * scaleTransform.ScaleX;
            translateTransform.Y = absoluteY - relative.Y * scaleTransform.ScaleY;
        }

    }
}

试试下面的代码,它对你有意义吗。

    private void MainImage_MouseMove(object sender, MouseEventArgs e)
    {
        // Don't drag when full scale and don't drag it if mouse not held down on image
        if (!MainImage.IsMouseCaptured || scaleTransform.ScaleX == 1)
        {
            return;
        }

        // Drag image by modifying X,Y coordinates
        var dragMousePosition = start - e.GetPosition(this);

        var newXproperty = origin.X - dragMousePosition.X;
        var newYproperty = origin.Y - dragMousePosition.Y;

        var isXOutOfBorder = this.MainBorderImage.ActualWidth < (this.MainImage.ActualWidth * this.scaleTransform.ScaleX);
        var isYOutOfBorder = this.MainBorderImage.ActualHeight < (this.MainImage.ActualHeight * this.scaleTransform.ScaleY);
        if ((isXOutOfBorder && newXproperty> 0) || (!isXOutOfBorder && newXproperty < 0))
        {
            newXproperty = 0;
        }
        if((isYOutOfBorder && newYproperty > 0) || (!isYOutOfBorder && newYproperty < 0))
        {
            newYproperty = 0;
        }
        var maxX = this.MainBorderImage.ActualWidth - (this.MainImage.ActualWidth * this.scaleTransform.ScaleX);
        if ((isXOutOfBorder && newXproperty < maxX) || (!isXOutOfBorder && newXproperty > maxX))
        {
            newXproperty = maxX;
        }
        var maxY = this.MainBorderImage.ActualHeight - (this.MainImage.ActualHeight * this.scaleTransform.ScaleY);
        if ((isXOutOfBorder && newYproperty < maxY) || (!isXOutOfBorder && newYproperty > maxY))
        {
            newYproperty = maxY;
        }

        translateTransform.X = newXproperty;
        translateTransform.Y = newYproperty;

        e.Handled = true;
    }