詳解WPF Blend工具中的復合路徑功能 ( 含路徑標記語法 )


寫此文章的目的是為了簡單分析一下 Blend工具中提供的"復合路徑"功能.有人在我的博文中留言問我復合路徑的問題. 

稍微琢磨一下,覺得應該是對的.因此貼出來和大家分享.有不對的說錯的歡迎指正.

 


 

在此之前我們先了解一下WPF的"路徑標記語法"

M:表示繪制起點 // M 0,0

L:表示繪制直線 (H:橫線 V:豎線)  // L 100,0

C:三次方貝塞爾曲線   // C 100,200 200,400 300,200

Q: 二次曲線

z:閉合

......

要注意的是 每一次的繪制都是基於上一次的終點(或者原點M)

例如 M 0,0 L 100,0 L200,50 表示 移動繪制原點到(0,0) 然后繪制直線(100,0) 緊接着從(100,0)開始再繪制直線到(200,50),也就是說每一次繪制命令都是接着上一次開始的.

*手寫語法命令的時候注意空格的使用,以及逗號的使用.

等等 MSDN有詳細介紹 不了解的可以去看看.

大致了解路徑標記語法后我們來探討一下"復合路徑"功能.

首先我們繪制兩條線

(一)

<Canvas >
    <Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
    <Path Data="M100,0 L250,120 "  Stretch="Fill" Stroke="green" StrokeThickness="5"/>
</Canvas>

看下效果

           

我們在看Blend->復合路徑后的代碼

<Path Data="M2.5,2.5 L52.5,122.5 M2.5,2.5 L152.5,122.5" Stretch="Fill" Stroke="red" StrokeThickness="5" />

我們仔細觀察 復合前的2個Path.Data的語法和復合后的Path.Data的差別.

看看看看看看....嗯... IQ處理中......................

我們把前兩個拼起來看看!

//拼前:
    <Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
        <Path Data="M100,0 L250,120 "  Stretch="Fill" Stroke="green" StrokeThickness="5"/>

//拼后 :

<Path Data="M0,0 L50,120  M100,0 L250,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>

// Blend復合的:

<Path Data="M2.5,2.5 L52.5,122.5 M2.5,2.5 L152.5,122.5" Stretch="Fill" Stroke="red" StrokeThickness="5" />

看看后兩個Path有什么一樣的地方嗎?!

是的 Blend好像也是給拼接起來的? 可是為什么有2.5的誤差呢?為什么每個數都是2.5 怎么不是0.1不是其他呢?  奧秘就在這里:StrokeThickness="5"

 

2.5正好是5的一半嘛,是的,這個2.5只是算了粗細而已.我們可以去掉它也不會影響整體的形狀的.

當我們把5改為1后(什么你說改成0?? 0像素好粗啊 會閃下我氪金狗眼的!別鬧~~~)

再使用復合路徑得到的數據是 M0.5,0.5 L50.5,120.5 M0.5,0.5 L150.5,120.5 , 看看"誤差"變為0.5了吧.如果你手動去掉所有的小數,那么你會看到形狀不變的.這里我就不去演示了.

那么我們初步得到結論:復合路徑 =路徑1+路徑2+路徑3+..... (拼接所有的路徑部分) .

 

(二)

下面我們再來看一組數據:

    <Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
        <Path Data="M100,0 L300,120 " Canvas.Left="50" Stretch="Fill" Stroke="red" StrokeThickness="5"/>

效果:

在看Blend復合后的代碼:

<Path Data="M2.5,2.5 L52.5,122.5 M52.5,2.5 L252.5,122.5" Stretch="Fill" Stroke="red" StrokeThickness="5" />

首先我們基於(一)的結論忽略掉粗細誤差2.5(順便驗證一下這個結論)得到結果

<Path Data="M0,0 L50,120 M50,0 L250,120" Stretch="Fill" Stroke="red" StrokeThickness="5"  />

Blend中我們看到形狀位置都沒變.

接下來我們嘗試手動拼接上面(二)的2個Path得到

        <Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
        <Path Data="M100,0 L300,120 " Canvas.Left="50" Stretch="Fill" Stroke="green" StrokeThickness="5"/>

手動拼接:

        <Path Data="M0,0 L50,120 M100,0 L300,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>

這是為什么? 怎么分離的這么遠? 

我們來解密一下:

看看第二條Path 他有這個附加屬性   Canvas.Left="50"   居然給右移了50!!!! 那么我們給他挪回去試試?

得到 

<Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
        <Path Data="M100,0 L300,120 " Canvas.Left="50" Stretch="Fill" Stroke="green" StrokeThickness="5"/>

手動拼接:

        <Path Data="M0,0 L50,120 M100,0 L300,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>
 
         
把第二個Path的Left 50 左移回去得到: <Path Data="M0,0 L50,120 M50,0 L250,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>
左移后 <Path Data="M0,0 L50,120 M50,0 L250,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>效果:


是不是一樣了!  左移第二條線是移動原點M和L的橫坐標 所以得到M50,0 L250,120"
( 被左移 - X需要減掉相應值 . 被右移 - X需要加上相應值 )
上下移同理,上移(Top負數)需加,下移(Top正數)需減
這個過程我們暫且稱為"復位"
因此我們又得到一個結論 Canvas.Left 同樣會影響復合路徑!當然這里也包括Canvas.Top /Right/Bottom  ,
值得提醒的是當 Left /Top等 的值為負數時  直接簡單拼接和"復位" 是不對的.因為你可能復不到位.不信你試試看.

這里稍微解釋一下標記語法一個特別的地方(我猜的!沒有去MSDN考證.)
<Path Data="M100,0 L300,120 "  Stretch="Fill" Stroke="green" StrokeThickness="5"/>
<Path Data="M0,0 L200,120 "  Stretch="Fill" Stroke="green" StrokeThickness="5"/>
<Path Data="M-100,0 L100,120 "  Stretch="Fill" Stroke="green" StrokeThickness="5"/>
這3個Path是一樣的!
當Path中只有一段圖形時(這里是只有一段Line) , Line整體平移(指的是原點從0,0 平移到100,0 且 端點從200,120平移到300,120)是不會影響Path形狀和位置的.
因此在只有一段圖形的Path中我們可以約掉這個平移 我們暫且稱為"約分"(參考數學分數的約分哈,不嚴謹 好記而已~~)

所以上面我說 當Canvas.Left為負數時 不能簡單直接拼接和復位.怎么辦呢?我們需要先約分!先把所有能約分的線段的原點約分到不能再約分的實際原點,
例如上面的三個Path的實際原點其實都是M 0,0  .約分處理完所有圖形片段后 再進行 拼接和復位.最后就能得到復合路徑的結果了.

另外,凡是所有能影響Path位置的屬性改變都會影響復合路徑的結果,比如 RenderTransform  和Margin 等.

如果想手動去算復合路徑可能是非常繁瑣的一個過程~~~ 您可能需要為所有影響Path位置變化的屬性改變都寫一個復位的方法.在執行復合路徑之前需要先調用所有的復位/約分方法來恢復Path的Data到實際值.再進行拼接計算.

以上是我粗略分析后的一些看法和結論.我之前也不知道這些的,只不過是在我的一片自定義MessageBox的文章中有人問我這個問題,我就試着猜猜.
這位童鞋@距離永遠  您可請俺喝酒啊!! 嘻嘻~~

如果哪位童鞋有在code中動態計算路徑的需求,不妨參考一下此文.
在下拙見,若有達人,不吝賜教!


/*******************************************************/

歡迎轉載!歡迎拍磚!

版權所有 © Vito野子

E-mail: vito2015@live.com

轉載請注明出處 http://www.cnblogs.com/Vito2008/p/CompoundPath.html

 /*******************************************************/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM