我是WPF的新手,正在尝试编写可点击的缩放平移图像控件。我已经有一个似乎有效的缩放平移图像:
<Border Name="border" ClipToBounds="True">
<Canvas>
<Image Name ="image">
Source="{Binding Path=Source}"
MouseLeftButtonDown="image_MouseLeftButtonDown"
MouseLeftButtonUp="image_MouseLeftButtonUp"
MouseMove="image_MouseMove"
MouseWheel="image_MouseWheel">
</Image>
</Canvas>
</Border>
对于鼠标和滚轮事件,我使用了这篇文章:http://www.codeproject.com/Articles/168176/Zooming-and-panning-in-WPF-with-fixed-focus
我通过继承ZoomPanImage并为LeftMouseUp添加事件来编写可点击控件。
public class ClickableImage : PanZoomImage
{
public event Action<Point> Click;
//...
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
// ... all sorts of checks to distinguish click from mouse move
if (Click != null)
{
Click(ControlToImage(mouseUpCoordinates));
}
}
protected Point ControlToImage(Point controlPixel)
{
//this is where i am stuck...
}
}
我的问题是,在给定控制坐标的情况下,我似乎无法计算出正确的图像坐标。我需要考虑到图像可以缩放和平移,窗口本身可以调整大小。
我尝试使用渲染变换。当我缩放并平移图像时,我更新了变换。当我尝试将控制坐标转换为图像坐标时,我使用逆变换:
Point imagePixel = image.RenderTransform.Inverse.Transform(controlPixel);
但是这没用。其中一个问题是Transform以Identity开头,而实际上图像被均匀拉伸到控件的大小。
谢谢, 迪娜
答案 0 :(得分:1)
以下是我如何解决它。正如Clemens建议的那样,我将图像拉伸模式设置为无。
<Image Name="image" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="None"
Source="{Binding Path=Source}"
MouseLeftButtonDown="image_MouseLeftButtonDown"
MouseLeftButtonUp="image_MouseLeftButtonUp"
MouseMove="image_MouseMove"
MouseWheel="image_MouseWheel"
Loaded="image_Loaded">
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Fit to window" Click="FitToWindow_MenuItem_Click"></MenuItem>
</ContextMenu>
</Image.ContextMenu>
</Image>
这意味着当图像加载到窗口中时,您只能看到它的一部分 - 具体取决于窗口大小。这很糟糕,但重要的是变换是身份,现在您可以手动设置它,使图像完全显示在窗口中。
private void FitViewToWindow()
{
if (Source == null)
throw new InvalidOperationException("Source not set");
BitmapSource bitmapSource = Source as BitmapSource;
if (bitmapSource == null)
throw new InvalidOperationException("Unsupported Image Source Type");
if (border.ActualWidth <= 0 || border.ActualHeight <= 0)
return;
double scaleX = border.ActualWidth / bitmapSource.PixelWidth;
double scaleY = border.ActualHeight / bitmapSource.PixelHeight;
double scale = Math.Min(scaleX, scaleY);
Matrix m = Matrix.Identity;
m.ScaleAtPrepend(scale, scale, 0, 0);
double centerX = (border.ActualWidth - bitmapSource.PixelWidth * scale) / 2;
double centerY = (border.ActualHeight - bitmapSource.PixelHeight * scale) / 2;
m.Translate(centerX, centerY);
image.RenderTransform = new MatrixTransform(m);
}
应在加载图像和更改图像源时调用此函数。至于调整窗口大小 - 只要跟踪变换,就可以正确转换坐标系。例如,这是我为窗口调整大小做的事情:
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
//center the image in the new size
if (sizeInfo.PreviousSize.Width <= 0 || sizeInfo.PreviousSize.Height <= 0)
return;
Matrix m = image.RenderTransform.Value;
double offsetX = (sizeInfo.NewSize.Width - sizeInfo.PreviousSize.Width) / 2;
double offsetY = (sizeInfo.NewSize.Height - sizeInfo.PreviousSize.Height) / 2;
m.Translate(offsetX, offsetY);
image.RenderTransform = new MatrixTransform(m);
}