平移和缩放,但在父容器中包含图像
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;
}
我正在开发自己的图像查看器,想平移和缩放图像。目前使用“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;
}