1. 程式人生 > >WPF 的Canvas畫圖區整體縮放

WPF 的Canvas畫圖區整體縮放

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)是可行的。這一點需要慢慢理解。