2012-02-20 45 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); 
}