WPF 的Canvas画图区整体缩放与平移(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiuzaizuotian2014/article/details/82659157

WPF对象都具有RenderTransform的属性,可以通过设置RenderTransform来对WPF的元素进行变换,无论是控件还是形状都可以变换。典型的变换包括缩放和平移:

(一)缩放

如果采用Canvas作为画板来绘制一些形状,想要通过鼠标或触摸操作来进行放大或缩小,那么不能简单地对canvas进行变换,否则Cancas放大的时候就会覆盖周边的其它控件,也就是Canvas占据的屏幕变大了或缩小了,而不仅仅是Canvas内部画出来的形状变大了或缩小了。

那如果需要实现放大或缩小怎么办呢?我采取的方式是在Canvas外面包装一个WPF元素,比如Border元素。这样,Canvas就成为Border元素的子元素了,然后在Border元素上实现鼠标控制操作来变换Canvas元素。

  <Border Name="outside" Grid.Row="1" Background="LightBlue" PreviewMouseDown="outsidewrapper_PreviewMouseDown" ClipToBounds="True">
            <Canvas Name="inside"   Width="{Binding Path=ActualWidth,RelativeSource={RelativeSource AncestorType=Border}}" 
                    Height="{Binding Path=ActualHeight,RelativeSource={RelativeSource AncestorType=Border}}">
                <Rectangle Canvas.Left="150" Canvas.Top="150" Width="380" Height="296" Fill="Red"/>
            </Canvas>
        </Border>
        private void outsidewrapper_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
           // Point p = e.GetPosition(inside);  //不能用这个,应该删除这一行


            Point po = e.GetPosition(outside);
            TransformGroup tg=  inside.RenderTransform as TransformGroup;
            if (tg == null)
                tg = new TransformGroup();
            tg.Children.Add(new ScaleTransform(0.6, 0.6, po.X, po.Y));  //centerX和centerY用外部包装元素的坐标,不能用内部被变换的Canvas元素的坐标
            inside.RenderTransform = tg;
        }

需要注意事项包括:

(1)包装的元素需要添加ClipToBounds="True"属性,这样当放大时,内部Canvas超出包装元素的时候,超出部分就会被裁剪掉;

(2)把Canvas元素的初始大小设置为与包装元素一样大小,可以通过RelativeSource来设置:Width="{Binding Path=ActualWidth,RelativeSource={RelativeSource AncestorType=Border}}" ,Height="{Binding Path=ActualHeight,RelativeSource={RelativeSource AncestorType=Border}}"。

(3)将外包包装元素的背景和Canvas的背景设置为一样的背景,这样当Canvas缩小的时候,不会给然感觉Canvas画布真的小了。或者Canvas不设置背景也是可行的(但可能Canvas会收不到鼠标事件......)。

(4)用鼠标事件控制放大缩小的话,可以使用隧道事件,且事件应该关联在外部包装元素Border上。放大或缩小的时候,放大缩小中心点(CenterX,CenterY)用的不是Canvas的坐标点,而是外部包装元素的坐标点。当然具体根据需要采用合适的事件,比如滚轮事件之类的,触控事件之类的。

(5)理解:按理说所有元素的变换都是针对自身的坐标体系的,而不是针对外部父元素的坐标体系的,但是WPF有个特点,虽然时针对自身坐标系的变化,但是变换前后自身的ActualWidth和ActualHeight都没有发生任何变化,下次继续变换的时候,还是用的ActualWidth和ActualHeigth作为自身坐标系的参考用途,而不是按照变换后的实际尺寸在定位自身坐标系尺寸的。所以,使用外部包装元素的坐标系来给定每次变换的(CenterX和CenterY)是可行的。这一点需要慢慢理解。

(二)平移

(见下一篇文章)

猜你喜欢

转载自blog.csdn.net/jiuzaizuotian2014/article/details/82659157
WPF
今日推荐