充分利用界面上的空間,是優秀軟件界面布局設計的原則之一。如果布局上出現了大片的空白區域就會給人一種浪費和不諧調的感覺。如下 圖所示。
我們把ListBox的ItemsPanel設置為一個WrapPanel。讓裡面的Items可以自動折行。但是這樣在ListBox的右側,會出現一塊空白區。很多情 況下,我們對於Item的大小並不很在意,這時我們會更希望Item的寬度可以隨著整體寬度自動地調節。產生如下圖所示的效果。
但是系統自帶的WrapPanel是做不到這一點的。這時我們就要用到自定義Panel了。看到上面的效果,可能有人會說用 UniformGrid不就行了 ?如果裡面的Item 一直是像上面3*6的固定布局是可以用UniformGrid的。或是你願意動態計算UniformGrid有幾行幾列也可以。WrapPanel的特 點是能動態地根據寬度調節每行Item的個數。如下圖所示。
上面的自動縮放的WrapPanel的效果還是通過自定義Panel來實現的。類圖如下。
使用這種方式進行布局,需要對這個FillWrapPanel裡的Item有一些特殊的要求。
1. 不設置寬度、最小寬度、最大寬度。這些都在FillWrapPanel設置。
2. 支持縮放。當Item變大時,內部布局也要隨之改變,並保持合理布局。說得簡單點。Item和Item內部的所有東西(TextBlock除外),都 不要設置固定的寬度和高度即可。
隨便說幾句關於自定義Panel的題外話。
在之前的文章中,已經介紹過兩種自定義Panel。一種是有縮放的,一種也是Wrap的。有人可能要問,能不能把這兩種Panel結合起來做一個 天下無雙的無比強大的Panel呢?答案是,如果有特定的規則來約束,是可以的。這個規則要滿足下面的要求。
在此規則的約束下,通過界面的大小,可以唯一地確定內部所有Item的布局(大小和位置)。
這個聽上去很費話,但是在自己實現一個Panel的過程中,很容易陷入邏輯之中,而忽視了這個簡單的約束條件。所以如果能定義出規則滿 足上面的條件,邏輯上就可以實現出這樣的Panel。但是作為一個第三方控件,你還要考慮到使用者的理解力。如果一個Panel的正確使用要靠 長篇的文檔和豐富的示例來保證。那這個Panel多數會被閒置,因為很少有布局會復雜到同時具有這些功能。即使做得出來,用戶用上去,也會 覺得奇怪。最優美的,也應該是最自然的。
在多數情況下,應該考慮用多個Panel的組合來實現復雜功能,而不是試圖實現一個無比強大的自定義Panel。這才是符合軟件設計模式的基 本要求的。
我們言歸正傳。從上面的Panel的類圖中,其實也就可以看出其實現方式。先計算出每行需要放置多少個Item,再計算出第個Item的寬度也 就行了。
單獨介紹一下FloorItemWidth的作用,這個屬性用來設置是否讓每個Item的寬度一定是個整數。如果寬度不是整數,TextBlock、Image等內 容可能會變得很模糊。
本文配套源碼