WPF Image zoom in and out around the mouse center

//uc.xaml
<UserControl x:Class="WpfApp180.UCImgZoom"
             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:WpfApp180"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Image x:Name="img"
               Source="{Binding UCImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
               MouseWheel="img_MouseWheel"
               Width="{Binding ActualWidth,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}"
               Height="{Binding ActualHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}"
                   >
            <Image.RenderTransform>
                <TransformGroup>
                    <ScaleTransform x:Name="scaler"/>
                    <TranslateTransform x:Name="translater"/>
                </TransformGroup>
            </Image.RenderTransform>
        </Image>
    </Grid>
</UserControl>


//uc.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp180
{
    /// <summary>
    /// Interaction logic for UCImgZoom.xaml
    /// </summary>
    public partial class UCImgZoom : UserControl
    {
        public UCImgZoom()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private void img_MouseWheel(object sender, MouseWheelEventArgs e)
        { 
            double zoom = e.Delta > 0 ? 1.2 : 1 / 1.2;             
            Point mousPos = e.GetPosition(img);
            double newScale = scaler.ScaleX * zoom;            
            double deltaX = (mousPos.X * (1 - zoom)) * scaler.ScaleX;
            double deltaY = (mousPos.Y * (1 - zoom)) * scaler.ScaleY;                        
            scaler.ScaleX = newScale;
            scaler.ScaleY = newScale;
            translater.X += deltaX;
            translater.Y += deltaY;
        }


        public ImageSource UCImgSource
        {
            get { return (ImageSource)GetValue(UCImgSourceProperty); }
            set { SetValue(UCImgSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCImgSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCImgSourceProperty =
            DependencyProperty.Register("UCImgSource", typeof(ImageSource), 
                typeof(UCImgZoom), new PropertyMetadata(null));


    }
}




//main.xaml
<Window x:Class="WpfApp180.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp180"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:UCImgZoom
            UCImgSource="{Binding ImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,
            RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}"/>
    </Grid>
</Window>


//main.xaml.cs



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;

namespace WpfApp180
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            string url = @"../../Images/1.jpg";
            ImgSource=GetImageSourceViaUrl(url);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }


        private ImageSource imgSource;
        public ImageSource ImgSource
        {
            get
            {
                return imgSource;
            }
            set
            {
                if (imgSource != value)
                {
                    imgSource = value;
                    OnPropertyChanged(nameof(ImgSource));
                }
            }
        }

        private ImageSource GetImageSourceViaUrl(string url)
        {
            if(!File.Exists(url))
            {
                return null;
            }
            BitmapImage bmi = new BitmapImage();
            bmi.BeginInit();
            bmi.UriSource=new Uri(url,UriKind.RelativeOrAbsolute);
            bmi.EndInit();
            if(bmi.CanFreeze)
            {
                bmi.Freeze();
            }
            return bmi;
        }
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2025-03-16 18:56  FredGrit  阅读(25)  评论(0)    收藏  举报