2012-02-20 43 views
1

我是WPF的新手,正在尝试编写可点击的缩放平移图像控件。我已经有一个缩放 - 摇动图像,这似乎工作:PanZoomImage的像素选择

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

但是这并不奏效。其中一个问题是变换是以身份开始的,而实际上图像被均匀地拉伸到控件的大小。

感谢, 迪娜

+0

请确保您设置[Image.Stretch(http://msdn.microsoft.com/en-us/library/system.windows.controls。 image.stretch.aspx)属性设置为'None',然后应用RenderTransform。 – Clemens 2012-02-20 18:36:40

+0

@Clemens,是的,我做到了。这个解决方案的问题是,最初的图像比窗口大。我希望根据窗口大小调整大小。所以我尝试添加一个回调函数,它在图像源被更改后立即调用,并将更改变换。但是这不起作用,因为当回调被称为image.actualHeight和image.actualWidth仍然是0 ... – Dina 2012-02-20 19:54:37

+0

当你设置Source属性(我假设在代码后面),你将它设置为一些[ImageSource](http: //msdn.microsoft.com/en-us/library/system.windows.media.imagesource.aspx) - 派生类,例如的BitmapSource。从ImageSource的Width和Height属性获取图像大小,并相应地设置RenderTransform。无论如何,如果你想手动执行,你必须避免自动缩放。 – Clemens 2012-02-20 20:22:09

回答

1

这里是我如何解决它。正如克莱门斯建议的那样,我将图像拉伸模式设置为无。

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