0

I've been following the most voted answer from here. Pan & Zoom Image ( the one with ZoomBorder.cs).

Everything works fine if I include that into my project. However my project is a ReactiveUI application, and i struggling to replicate that code using ReactiveUI design patters.

What I have done so far :

Created a new UserControl

<UserControl x:Class="ImageViewer.Controls.ZoomControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ImageViewer.Controls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Border BorderThickness="10" BorderBrush="Red">
        <Image x:Name="RenderingImage" RenderTransformOrigin="0,0" Stretch="None" Source="{Binding}" ClipToBounds="True">
            <Image.LayoutTransform>
                <TransformGroup>
                    <ScaleTransform x:Name="ImageScale" ScaleX="{Binding}" ScaleY="{Binding}"/>
                    <TranslateTransform x:Name="ImageTranslate" X="{Binding}" Y="{Binding}" />
                </TransformGroup>
            </Image.LayoutTransform>
        </Image>
    </Border>
</UserControl>

Added binding between View->ViewModel

 public partial class ZoomControl : IViewFor<ZoomControlViewModel>
    {
        public static readonly DependencyProperty ViewModelProperty = DependencyProperty
       .Register(nameof(ViewModel), typeof(ZoomControlViewModel), typeof(ZoomControl), null);
        public ZoomControl()
        {
            InitializeComponent();

            this.DataContextChanged += (sender, args) => ViewModel = DataContext as ZoomControlViewModel;

            this.WhenActivated(cleanup =>
            {
                this.OneWayBind(ViewModel, vm => vm.ImageSource, v => v.RenderingImage.Source).DisposeWith(cleanup);

                this.OneWayBind(ViewModel, vm => vm.ScaleX, v => v.ImageScale.ScaleX).DisposeWith(cleanup);
                this.OneWayBind(ViewModel, vm => vm.ScaleY, v => v.ImageScale.ScaleY).DisposeWith(cleanup);
                this.OneWayBind(ViewModel, vm => vm.TranslateX, v => v.ImageTranslate.X).DisposeWith(cleanup);
                this.OneWayBind(ViewModel, vm => vm.TranslateY, v => v.ImageTranslate.Y).DisposeWith(cleanup);

                RenderingImage.Events().MouseWheel.Select(e => new Tuple<int, Point>(e.Delta, e.GetPosition(RenderingImage))).InvokeCommand(ViewModel.ZoomAction).DisposeWith(cleanup);
            });
        }

        public ZoomControlViewModel ViewModel { get => (ZoomControlViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); }
        object IViewFor.ViewModel { get => ViewModel; set => ViewModel = (ZoomControlViewModel)value; }
    }

In view model I have the zoom command implemented like this .

 public ZoomControlViewModel()
        {
            ZoomAction = ReactiveCommand.Create<Tuple<int, Point>>(z => Zoom(z));
        }

private void Zoom(Tuple<int, Point> deltaArgs)
        {
            int delta = deltaArgs.Item1;
            Point relativePosition = deltaArgs.Item2;

            //var ScaleTransform = GetScaleTransform();
            //var TranslateTransform = GetTranslateTransform();

            double zoom = delta > 0 ? .2 : -.2;
            if (!(delta > 0) && (ScaleX < .4 || ScaleY < .4))
                return;

            double absoluteX;
            double absoluteY;

            absoluteX = relativePosition.X * ScaleX + TranslateX;
            absoluteY = relativePosition.Y * ScaleY + TranslateY;

            ScaleX += zoom;
            ScaleY += zoom;

            TranslateX = absoluteX - relativePosition.X * ScaleX;
            TranslateY = absoluteY - relativePosition.Y * ScaleY;
        }

Now my question. For this example above zooming works fine, but it does not zoom to mouse position it zooms to LeftUp corner of the image.

From my knowledge ( here might be the problem) changing the TranslateTransform of the image (TranslateX and TranslateY) should zoom me to the current mouse position.

Any tips would be appreciated.

CiucaS
  • 2,010
  • 5
  • 36
  • 63
  • `ScaleTransform` has `CenterX` and `CenterY` properties that defines the coordinates of the center points. How is this related to ReactiveUI? – mm8 Feb 25 '20 at 12:55
  • @mm8 they are not related in any way. I haven't touched CenterX and CenterY, I haven't seen them used in the example I took as example – CiucaS Feb 25 '20 at 13:01
  • But I don't want to zoom from the center, I want to zoom from the current mouse position. What triggers me, is that I use the exact same code only made it reactive and it seems that TranslateX/TranslateY does change but on the image it does not. It feels like the binding is ignored. – CiucaS Feb 25 '20 at 13:13
  • Sometimes the warning messages can give you more information on rxui binding issues. – Glenn Watson Feb 25 '20 at 13:19
  • Found the problem, it was not the rxui binding, it was the fact that TranslateTransform is immutable. So the binding works, but the update is not done because of the TranslateTransform immutability. – CiucaS Feb 25 '20 at 13:41

0 Answers0