I have scrollViewer in WinUI 3 that contain Image and when I press double click on mouse I want to zoom in/out image and center the image to position of my cursor. I do this code for zoom in/out on double click scrollViewer:
private void Scroll_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
var zoom = scroll.ZoomFactor == 1 ? 3 : 1;
scroll.ChangeView(null, null, zoom, true);
ZoomSlider.Value = zoom;
}
now I try to center my image to position of cursor and I try like this:
private void Scroll_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
var zoom = scroll.ZoomFactor == 1 ? 3 : 1;
var pointerPosition = e.GetPosition(scroll);
scroll.ChangeView(pointerPosition.X, pointerPosition.Y, zoom, true);
ZoomSlider.Value = zoom;
}
but its not center to position of my cursor. what can I do?
this my code in .xaml file:
<Slider x:Name="ZoomSlider" Width="200" Maximum="5" StepFrequency="0.1" ValueChanged="ZoomSlider_ValueChanged" Margin="0,5,0,0" />
<ScrollViewer x:Name="scroll" ZoomMode="Enabled" Grid.Row="1"
MinZoomFactor="1" MaxZoomFactor="5.0"
IsTabStop="True"
IsVerticalScrollChainingEnabled="True"
IsHorizontalScrollChainingEnabled="True"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollMode="Enabled"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollMode="Enabled"
VerticalScrollBarVisibility="Hidden"
ViewChanged="ScrollViewer_ViewChanged">
<Image x:Name="MyImage"
Source="{x:Bind ViewModel.Image, Mode=OneWay}"
PointerPressed="Image_PointerPressed"
PointerMoved="Image_PointerMoved"
PointerReleased="Image_PointerReleased"
DoubleTapped="Image_DoubleTapped"
Stretch="Uniform" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</ScrollViewer>
and this is my code behind from xaml.cs file:
internal abstract class ImageBasePage : BasePage<ImageViewModel> { }
internal sealed partial class ImagePage : ImageBasePage
{
bool _isSyncing = false, _isDragging = false, _isManualZoomChange = false;
double _initialHorizontalOffset, _initialVerticalOffset;
public ImagePage()
{
this.InitializeComponent();
}
private void Scroll_SizeChanged(object sender, SizeChangedEventArgs e)
{
MyImage.MaxHeight = scroll.ActualHeight;
MyImage.MaxWidth = scroll.ActualWidth;
}
private void ZoomSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
if (!_isSyncing && !_isManualZoomChange)
{
_isSyncing = true;
scroll.ChangeView(null, null, (float)e.NewValue);
_isSyncing = false;
}
}
private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (!_isSyncing && !_isManualZoomChange)
{
_isSyncing = true;
ZoomSlider.Value = scroll.ZoomFactor;
_isSyncing = false;
}
}
private void Image_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
_isManualZoomChange = true;
if (sender is not Image image)
{
return;
}
var pointerPoint = e.GetPosition(image);
float zoomFactor = scroll.ZoomFactor;
float nextZoomFactor = zoomFactor == 1 ? 3 : 1;
double nextHorizontalOffset = Math.Max(pointerPoint.X * nextZoomFactor - (scroll.ViewportWidth / 2), 0);
double nextVerticalOffset = Math.Max(pointerPoint.Y * nextZoomFactor - (scroll.ViewportHeight / 2), 0);
_ = scroll.ChangeView(nextHorizontalOffset, nextVerticalOffset,nextZoomFactor,true);
ZoomSlider.Value = nextZoomFactor;
_isManualZoomChange = false;
}
private void Image_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (_isDragging)
{
var currentPoint = e.GetCurrentPoint(scroll).Position;
var deltaX = currentPoint.X - _initialPoint.X;
var deltaY = currentPoint.Y - _initialPoint.Y;
scroll.ChangeView(_initialHorizontalOffset - deltaX, _initialVerticalOffset - deltaY, null);
}
}
private void Image_PointerReleased(object sender, PointerRoutedEventArgs e)
{
_isDragging = false;
(sender as UIElement).ReleasePointerCapture(e.Pointer);
}
}
You need to take ViewportWidth and ViewportHeight into consideration. The following should work:
<ScrollViewer
x:Name="ScrollViewer"
HorizontalScrollBarVisibility="Auto"
MinZoomFactor="1"
MaxZoomFactor="10"
PointerMoved="ScrollViewer_PointerMoved"
VerticalScrollBarVisibility="Auto"
ZoomMode="Enabled">
<Image
DoubleTapped="Image_DoubleTapped"
Source="/Assets/test.png" />
</ScrollViewer>
private void Image_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (sender is not Image image)
{
return;
}
var pointerPoint = e.GetPosition(image);
float zoomFactor = this.ScrollViewer.ZoomFactor;
float nextZoomFactor = Math.Min(zoomFactor * 2.0f, this.ScrollViewer.MaxZoomFactor);
double nextHorizontalOffset = Math.Max(pointerPoint.X * nextZoomFactor - (this.ScrollViewer.ViewportWidth / 2), 0);
double nextVerticalOffset = Math.Max(pointerPoint.Y * nextZoomFactor - (this.ScrollViewer.ViewportHeight / 2), 0);
_ = this.ScrollViewer.ChangeView(
nextHorizontalOffset,
nextVerticalOffset,
nextZoomFactor);
}