Вот как я это решил. Как предложил Клеменс, я установил режим растягивания изображения на 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>
Это означает, что когда изображение загружается в окно, вы можете видеть только его часть - в зависимости от размера окна. Это плохо, но важно то, что преобразование является тождественным, и теперь вы можете вручную установить его так, чтобы изображение полностью отображалось в окне.
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);
}