WPF - 在滚动查看器中放大图像,并相应地调整滚动条
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14729853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF - Zooming in on an image inside a scroll viewer, and having the scrollbars adjust accordingly
提问by JMK
I have put together a simple WPF application to demonstrate the issue I am having. My XAML is below:
我整理了一个简单的 WPF 应用程序来演示我遇到的问题。我的 XAML 如下:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="427" Width="467" Loaded="MainWindow_OnLoaded">
<Grid>
<ScrollViewer Name="MyScrollViewer" CanContentScroll="True">
<Image Name="MyImage" HorizontalAlignment="Left" VerticalAlignment="Top" MouseWheel="UIElement_OnMouseWheel" MouseDown="MyImage_OnMouseDown" MouseUp="MyImage_OnMouseUp"/>
</ScrollViewer>
</Grid>
</Window>
The code-behind is below:
代码隐藏如下:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
var matrix = MyImage.RenderTransform.Value;
if (e.Delta > 0)
{
matrix.ScaleAt(1.5, 1.5, e.GetPosition(this).X, e.GetPosition(this).Y);
}
else
{
matrix.ScaleAt(1.0 / 1.5, 1.0 / 1.5, e.GetPosition(this).X, e.GetPosition(this).Y);
}
MyImage.RenderTransform = new MatrixTransform(matrix);
}
private WriteableBitmap writeableBitmap;
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
var image = new WriteableBitmap(new BitmapImage(new Uri(@"C:\myImage.png", UriKind.Absolute)));
MyImage.Width = image.Width;
MyImage.Height = image.Height;
image = BitmapFactory.ConvertToPbgra32Format(image);
writeableBitmap = image;
MyImage.Source = image;
}
private Point downPoint;
private Point upPoint;
private void MyImage_OnMouseDown(object sender, MouseButtonEventArgs e)
{
downPoint = e.GetPosition(MyImage);
}
private void MyImage_OnMouseUp(object sender, MouseButtonEventArgs e)
{
upPoint = e.GetPosition(MyImage);
writeableBitmap.DrawRectangle(Convert.ToInt32(downPoint.X), Convert.ToInt32(downPoint.Y), Convert.ToInt32(upPoint.X), Convert.ToInt32(upPoint.Y), Colors.Red);
MyImage.Source = writeableBitmap;
}
}
}
I have added WriteableBitmapEx using Nuget. If you run this, and replace myImage.pngwith the location of an actual image on your computer, you will find an application that looks something like this:
我使用 Nuget 添加了 WriteableBitmapEx。如果您运行它,并将myImage.png替换为您计算机上实际图像的位置,您会发现一个看起来像这样的应用程序:
You can draw a box on the image by clicking on the top-left of where you want the box to go and dragging to the bottom right of where you want the box to go, you get a red rectangle. You can even zoom in with the middle-mouse, and draw a rectangle up close for more precision, this works as expected.
您可以通过单击希望框所在位置的左上角并拖动到框所在位置的右下角,在图像上绘制一个框,您会得到一个红色矩形。您甚至可以使用鼠标中键放大,并近距离绘制一个矩形以获得更高的精度,这可以按预期工作。
The problem is that, when you scroll in with the middle mouse, the scroll bars don't re-adjust, which is a requirement of the program I am creating. My question is how do I force the scrollbars on the scrollviewer to re-adjust when the image is zoomed in?
问题是,当你用鼠标中键滚动时,滚动条不会重新调整,这是我正在创建的程序的要求。我的问题是如何强制滚动查看器上的滚动条在图像放大时重新调整?
I am convinced it has something to do with the RenderTransform property of the ScrollViewer, and that I need to update it at the same time I update the RenderTransform property of the image (on UIElement_OnMouseWheel) but I am unsure of exactly how to go about this.
我确信它与 ScrollViewer 的 RenderTransform 属性有关,并且我需要在更新图像的 RenderTransform 属性的同时更新它(在 UIElement_OnMouseWheel 上),但我不确定具体如何处理.
回答by John Bowen
You should be using LayoutTransform
instead of RenderTransform
on your Image.
您应该使用LayoutTransform
而不是RenderTransform
在您的图像上。
RenderTransform
happens after layout completes and is visual only. LayoutTransform
is done before the layout pass and so can notify the ScrollViewer
of the new size.
RenderTransform
布局完成后发生并且仅是可视的。LayoutTransform
在布局传递之前完成,因此可以通知ScrollViewer
新的大小。
See here for more info: http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.layouttransform.aspx
请参阅此处了解更多信息:http: //msdn.microsoft.com/en-us/library/system.windows.frameworkelement.layouttransform.aspx
回答by SvenG
For pure scrolling I'd rather use a ScaleTransform, it should adjust the scrollbars accordingly. You can try below code if it fixes your issue.
对于纯滚动,我宁愿使用 ScaleTransform,它应该相应地调整滚动条。如果它解决了您的问题,您可以尝试以下代码。
private double _zoomValue = 1.0;
private void UIElement_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
_zoomValue += 0.1;
}
else
{
_zoomValue -= 0.1;
}
ScaleTransform scale = new ScaleTransform(_zoomValue, _zoomValue);
MyImage.LayoutTransform = scale;
e.Handled = true;
}
回答by Wayne Lo
Let's assume you have a Canvas_Main inside a ViewBox_CanvasMain, which in turn inside a ScrollViewer_CanvasMain. You want to zoom in by turning the mouse wheel, and the ScrollViewer will adjust the offset automatically so the feature (pointed by the mouse in the Canvas_Main) stays during the zoom in/out. It is complex but here is the code called by the mouse wheel eventhandler:
假设您在 ViewBox_CanvasMain 中有一个 Canvas_Main,而后者又在 ScrollViewer_CanvasMain 中。您想通过转动鼠标滚轮来放大,ScrollViewer 将自动调整偏移量,以便在放大/缩小期间保持特征(由鼠标在 Canvas_Main 中指向)。它很复杂,但这里是鼠标滚轮事件处理程序调用的代码:
private void MouseWheelZoom(MouseWheelEventArgs e)
{
if(Canvas_Main.IsMouseOver)
{
Point mouseAtImage = e.GetPosition(Canvas_Main); // ScrollViewer_CanvasMain.TranslatePoint(middleOfScrollViewer, Canvas_Main);
Point mouseAtScrollViewer = e.GetPosition(ScrollViewer_CanvasMain);
ScaleTransform st = ViewBox_CanvasMain.LayoutTransform as ScaleTransform;
if (st == null)
{
st = new ScaleTransform();
ViewBox_CanvasMain.LayoutTransform = st;
}
if (e.Delta > 0)
{
st.ScaleX = st.ScaleY = st.ScaleX * 1.25;
if (st.ScaleX > 64) st.ScaleX = st.ScaleY = 64;
}
else
{
st.ScaleX = st.ScaleY = st.ScaleX / 1.25;
if (st.ScaleX < 1) st.ScaleX = st.ScaleY = 1;
}
#region [this step is critical for offset]
ScrollViewer_CanvasMain.ScrollToHorizontalOffset(0);
ScrollViewer_CanvasMain.ScrollToVerticalOffset(0);
this.UpdateLayout();
#endregion
Vector offset = Canvas_Main.TranslatePoint(mouseAtImage, ScrollViewer_CanvasMain) - mouseAtScrollViewer; // (Vector)middleOfScrollViewer;
ScrollViewer_CanvasMain.ScrollToHorizontalOffset(offset.X);
ScrollViewer_CanvasMain.ScrollToVerticalOffset(offset.Y);
this.UpdateLayout();
e.Handled = true;
}
}