2012-02-20 12 views
1

私はWPFを初めて使用しており、クリック可能なズームパン画像コントロールを作成しようとしています。 http://www.codeproject.com/Articles/168176/Zooming-and-panning-in-WPF-with-fixed-focusPanZoomImageのピクセル選択

私はZoomPanImageから継承し、イベントを追加することにより、クリック可能な制御を書いています:マウスホイールイベントでは

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

が、私はこのポストを使用:私はすでに動作しているようですズームパンイメージを持っています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); 

これはうまくいきませんでした。問題の1つは、変換がアイデンティティとして開始され、実際にはイメージがコントロールのサイズに均一に引き伸ばされることです。

おかげで、 ディナ

+0

あなたは[Image.Stretch](http://msdn.microsoft.com/en-us/library/system.windows.controlsを設定していることを確認してください。 image.stretch.aspx)プロパティを「None」に設定してから、RenderTransformを適用します。 – Clemens

+0

@クレメンス、はい、私はそれをしました。この解決法の問題点は、最初は画像がウィンドウよりも大きいことです。ウィンドウサイズに合わせてサイズを変更したい。そこで、画像のソースが変更された直後に呼び出され、変換を変更するコールバックを追加しようとしました。しかし、コールバックがimage.actualHeightとimage.actualWidthと呼ばれていたときにも0 ... – Dina

+0

ソースプロパティを設定すると(コードの後ろにあると仮定して)、[ImageSource](http: //msdn.microsoft.com/en-us/library/system.windows.media.imagesource.aspx)-誘導されたクラス、例えばBitmapSource。 ImageSourceのWidthプロパティとHeightプロパティからイメージサイズを取得し、それに応じてRenderTransformを設定します。とにかく、手動スケーリングをしたい場合は、自動スケーリングを避けなければなりません。 – Clemens

答えて

1

は、ここで私はそれを解決した方法です。 Clemensが示唆したように、私は画像ストレッチモードをnoneに設定しました。

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

これは、イメージがウィンドウに読み込まれると、ウィンドウのサイズによってはその一部しか表示できないことを意味します。これは悪いですが、重要なのは変換がIDであり、イメージがウィンドウに完全に表示されるように手動で設定できることです。

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