C# WPF 以鼠标中心的放大缩小和拖拽

这篇博客介绍了如何在C# WPF环境中实现以鼠标为中心的图像缩放和拖拽操作。作者强调了这种方法在图像预览中的常见应用,并指出WPF的相关资源相对较少。文章详细讲解了使用ContentControl和Image控件,通过MouseWheel、MouseDown和MouseMove事件来实现缩放和平移的功能。同时,提供了MVVM模式下的实现方式,使得代码更易于管理和维护。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以当前鼠标坐标的缩放和拖拽的方法,应用较多的有图像预览。

C#和WPF的框架比一些前端 或Java的UI框架,少了很多东西,作为开发者来说,社区生态的确非常重要。

网上关于WPF的资源不多,像基本的缩放和拖拽需要完全自己写代码。代码不复杂,为避免大家重复发明轮子,分享自己的代码给大家。

效果预览:

进入正题

1.前台代码:创建一个ContentControl(控件容器也行)包含一个Image控件。

  ContentControl有三个事件,分别是:MouseWheel,MouseDown和MouseMove。

 
 <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled" > 
<ContentControl MouseWheel="ContentControl_MouseWheel" MouseDown="ContentControl_MouseDown" MouseUp="ContentControl_MouseUp"  >
     <Image Name="ImgCtl" Margin="-2,2,0,0"  />
</ContentControl>
  </ScrollViewer>

  2. Image控件指定TransformGroup

所有缩放和平移操作都应用于Image控件。TransformGroup能容纳各种变换。在初始化时它的Children添加了ScaleTransformTranslateTransform,分别用于缩放平移的变换。

  public TransformGroup transGroup;

     private void Window_Loaded(object sender, RoutedEventArgs e)
        {
        transGroup.Children.Add(new ScaleTransform());
            transGroup.Children.Add(new TranslateTransform());
           ImgCtl.Rendertransform=transGroup;
        }

3. 缩放操作

MouseWheel:监听用户的鼠标滚动事件,进行缩放操作。 

        private void ContentControl_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
        {
            Control ctl = sender as Control;
            System.Windows.Point point = e.GetPosition(ctl);
            //滚轮滚动时控制 放大的倍数,没有固定的值,可以根据需要修改。
            double scale = e.Delta * 0.002;

            ZoomImage(transGroup, point, scale);
        }


        //对控件进行缩放。
        private void ZoomImage(TransformGroup group, Point point, double scale)
        {
            Point pointToContent = group.Inverse.Transform(point);

            ScaleTransform scaleT = group.Children[0] as ScaleTransform;

            if (scaleT.ScaleX + scale < 1) return;

            scaleT.ScaleX += scale;

            scaleT.ScaleY += scale;

            TranslateTransform translateT = group.Children[1] as TranslateTransform;

            translateT.X = -1 * ((pointToContent.X * scaleT.ScaleX) - point.X);

            translateT.Y = -1 * ((pointToContent.Y * scaleT.ScaleY) - point.Y);
        
        }

4. 拖拽操作

MouseDown:监听用户点击事件,记录拖拽前鼠标坐标和Image的坐标。 

          //用于保存鼠标点击时的位置
        System.Windows.Point  mousePosition = new System.Windows.Point();
        //鼠标点击时控件位置
        System.Windows.Point contentCtlPosition = new System.Windows.Point();


         private void ContentControl_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Control ctl = sender as Control;
            mousePosition = e.GetPosition(ctl);
            TranslateTransform tt = TransGroup.Children[1] as TranslateTransform;

            contentCtlPosition = new Point(tt.X, tt.Y);
        }

MouseMove:监听用户是否进行拖拽并做平移变换。

    private void MasterScrollViewer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Control ctl = sender as Control;
                Point desPosition = e.GetPosition(ctl);
            
                TranslateTransform transform = transGroup.Children[1] as TranslateTransform;
                  //控件移动位置的计算方式为:鼠标点击时位置+拖拽的长度(当前坐标-鼠标点击时的坐标).
                transform.X = contentCtlPosition.X + (desPosition.X - mousePosition.X);
                transform.Y = contentCtlPosition.Y + (desPosition.Y - mousePosition.Y);
               
            }
        }

 TransformGroup比常见的一个Canvsa父级控件然后Canvas.SetLeft()、Canvas.SetTop()....要方便许多。并且这种写法可以使用MVVM模式,不必再调用Canvas和Image实例。

到此所有操作都已完成。如果不用MVVM模式的写法可以直接略过下面的内容。

MVVM写法:

前台代码:

  xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
//在例子中使用MVVMLight 。如果不用,command可以用其它写法
         xmlns:command="http://www.galasoft.ch/mvvmlight"
       
 <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled">
               
                    <ContentControl  >
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="MouseMove">
                                <command:EventToCommand Command="{Binding MouseMoveCmd}" PassEventArgsToCommand="True" />
                            </i:EventTrigger>
                            <i:EventTrigger EventName="MouseWheel">
                                <command:EventToCommand Command="{Binding MouseWheelCmd}" PassEventArgsToCommand="True" />
                            </i:EventTrigger>
                            <i:EventTrigger EventName="MouseDown">
                                <command:EventToCommand Command="{Binding MouseDownCmd}" PassEventArgsToCommand="True" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                        <Image Margin="-2,2,0,0"  Source="{Binding PreviewImage}" RenderTransform="{Binding TransGroup}" >
                        </Image>
                    </ContentControl>
            </ScrollViewer>

 在VM中:


        //鼠标移动命令
        public RelayCommand<MouseEventArgs> MouseMoveCmd
        {
            get
            {
                return mouseMoveCmd ?? (mouseMoveCmd = new RelayCommand<MouseEventArgs>(OnMouseMove ));
            }
            private set { }
        }
        RelayCommand<MouseEventArgs> mouseMoveCmd;

         //鼠标滚动命令
        public RelayCommand<MouseWheelEventArgs> MouseWheelCmd
        {
            get
            {
                return mouseWheelCmd ?? (mouseWheelCmd = new RelayCommand<MouseWheelEventArgs>(OnMouseWheel));
            }
            private set { }
        }
        RelayCommand<MouseWheelEventArgs> mouseWheelCmd;

         //鼠标点击命令
        public RelayCommand<MouseButtonEventArgs> MouseDownCmd
        {
            get
            {
                return mouseDownCmd ?? (mouseDownCmd = new RelayCommand<MouseButtonEventArgs>(OnMouseDown));
            }
        }
        RelayCommand<MouseButtonEventArgs> mouseDownCmd;




       public TransformGroup TransGroup
        {
            get
            {
                return transGroup;
            }
            set
            {
                transGroup = value;
                RaisePropertyChanged();
            }
        }
        TransformGroup transGroup = new TransformGroup();

        //用于保存鼠标点击时的位置
        Point mousePosition = new Point();
        //鼠标点击时控件位置
        Point contentCtlPosition = new Point();


      //鼠标滚动,缩放控件。
      void OnMouseWheel(MouseWheelEventArgs args)
        {
            Control ctl = args.Source as Control;
            Point point = args.GetPosition(ctl);
            //滚轮滚动时控制 放大的倍数
            double scale = args.Delta * 0.002;

            ZoomImage(transGroup, point, scale);
        }

        //对控件进行缩放。
        private void ZoomImage(TransformGroup group, Point point, double scale)
        {
            Point pointToContent = group.Inverse.Transform(point);

            ScaleTransform scaleT = group.Children[0] as ScaleTransform;

            if (scaleT.ScaleX + scale < 1) return;

            scaleT.ScaleX += scale;

            scaleT.ScaleY += scale;

            TranslateTransform translateT = group.Children[1] as TranslateTransform;

            translateT.X = -1 * ((pointToContent.X * scaleT.ScaleX) - point.X);

            translateT.Y = -1 * ((pointToContent.Y * scaleT.ScaleY) - point.Y);
         
            RaisePropertyChanged("TransGroup");
        }


        //鼠标点击,记录下点击的位置。
        void OnMouseDown(MouseButtonEventArgs args)
        {
            Control ctl = args.Source as Control;
            
            if (ctl == null)
            {

            }
            mousePosition = args.GetPosition(ctl);
            TranslateTransform tt = TransGroup.Children[1] as TranslateTransform;

            contentCtlPosition = new Point(tt.X, tt.Y);
        }


        //鼠标移动,每次移动与上一次的位置相加,并实时更新当前位置。
        private void OnMouseMove(System.Windows.Input.MouseEventArgs args)
        {
            if (args.LeftButton == MouseButtonState.Pressed)
            {
                Control ctl = args.Source as Control;

                Point desPosition = args.GetPosition(ctl);

                TranslateTransform transform = transGroup.Children[1] as TranslateTransform;

               //控件移动位置的计算方式为:鼠标点击时位置+拖拽的长度(当前坐标-鼠标点击时的坐标).
                transform.X = contentCtlPosition.X + (desPosition.X - mousePosition.X);

                transform.Y = contentCtlPosition.Y + (desPosition.Y - mousePosition.Y);
                RaisePropertyChanged("TransGroup");
            }
        }


  
       

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值