2009-11-05 13 views
6

Próbuję dowiedzieć się WPF, więc tutaj jest to proste pytanie, mam nadzieję:Transformacja współrzędnych z kontrolą obrazu do źródła obrazu w WPF

Mam okno, które zawiera element obrazu związanego z oddzielnym danych Obiekt o konfigurowalne Stretch nieruchomość

<Image Name="imageCtrl" Source="{Binding MyImage}" Stretch="{Binding ImageStretch}" /> 

gdy użytkownik przesuwa kursor myszy nad obrazem, chciałbym, aby określić współrzędne myszy w stosunku do oryginalnego obrazu na (przed rozciąganiem/przycinania, która występuje, gdy jest wyświetlany w kontrolce), a następnie zrobić coś za pomocą t współrzędne węża (zaktualizuj obraz).

wiem, że można dodać obsługi zdarzeń do zdarzenia mouseMove nad kontrolą obrazu, ale nie jestem pewien, w jaki sposób najlepiej przekształcić współrzędne:

void imageCtrl_MouseMove(object sender, MouseEventArgs e) 
{ 
    Point locationInControl = e.GetPosition(imageCtrl); 
    Point locationInImage = ??? 
    updateImage(locationInImage); 
} 

Teraz wiem, mogłem porównać rozmiar z Source do ActualSize kontrolki, a następnie włącz imageCtrl.Stretch, aby obliczyć skalary i przesunięcia w X i Y, i sam dokonaj transformacji. Ale WPF ma już wszystkie informacje i wygląda na to, że funkcjonalność może być wbudowana w biblioteki WPF gdzieś. Zastanawiam się: czy istnieje krótkie i słodkie rozwiązanie? Czy muszę sam to napisać?


EDIT jestem dołączanie mój obecny, nie tak krótki i słodki rozwiązanie. Nie jest tak źle, ale byłbym nieco zaskoczony, jeśli WPF nie przewiduje tej funkcji automatycznie:

Point ImgControlCoordsToPixelCoords(Point locInCtrl, 
    double imgCtrlActualWidth, double imgCtrlActualHeight) 
{ 
    if (ImageStretch == Stretch.None) 
     return locInCtrl; 

    Size renderSize = new Size(imgCtrlActualWidth, imgCtrlActualHeight); 
    Size sourceSize = bitmap.Size; 

    double xZoom = renderSize.Width/sourceSize.Width; 
    double yZoom = renderSize.Height/sourceSize.Height; 

    if (ImageStretch == Stretch.Fill) 
     return new Point(locInCtrl.X/xZoom, locInCtrl.Y/yZoom); 

    double zoom; 
    if (ImageStretch == Stretch.Uniform) 
     zoom = Math.Min(xZoom, yZoom); 
    else // (imageCtrl.Stretch == Stretch.UniformToFill) 
     zoom = Math.Max(xZoom, yZoom); 

    return new Point(locInCtrl.X/zoom, locInCtrl.Y/zoom); 
} 
+0

Osobiście prawdopodobnie zrobiłbym to dokładnie tak, jak masz w swoim "nie tak krótkim i słodkim" rozwiązaniu. Nie wpadłem na wbudowaną bibliotekę, która by to zrobiła. –

Odpowiedz

7

Prawdopodobnie byłoby łatwiejsze, jeśli użył ViewBox. Na przykład:

<Viewbox Stretch="{Binding ImageStretch}"> 
    <Image Name="imageCtrl" Source="{Binding MyImage}" Stretch="None"/> 
</Viewbox> 

Kiedy wchodzisz i dzwonisz GetPosition (..) WPF automatycznie uwzględni skalowanie.

void imageCtrl_MouseMove(object sender, MouseEventArgs e) 
{ 
    Point locationInControl = e.GetPosition(imageCtrl); 
} 
+0

Dzięki. Stwierdziłem, że nie muszę ustawiać HorizontalAlignment, ale ważne było ustawienie DPI dla źródła obrazu na 96 (używałem niestandardowej mapy bitowej). Aha, a "b" w "Viewbox" jest małe :) – Gabriel

+0

Niesamowite! To niesamowite, jak łatwo można to zrobić w WPF! Wielkie dzięki, zaoszczędziłem mój czas. – Fedor