Trong bài trước, chúng ta đã tìm hiểu về StackPanel. Dễ thấy là chỉ với StackPanel, ta không thể tạo ra một giao diện người dùng hoàn hảo được. Và để khắc phục việc này, chúng ta thường sử dụng StackPanel với một số loại panel khác. Trước hết, chúng ta sẽ cùng tìm hiểu về WrapPanel.


The WrapPanel

WrapPanel bố trí các control vào những vùng trống trên cửa sổ của bạn, theo hàng hoặc cột. Mặc đinh, property WrapPanel.Orientation được set là Horizontal, tức là các control sẽ được sắp xếp từ trái sang phải và cứ như vậy với các hàng tiếp theo. Bạn cũng có thể set giá trị của property này lại thành Vertical nếu bạn muốn sắp xếp các elements theo cột.


Tip: cũng như StackPanel, WrapPanel thường được sử dụng để quản lí các chi tiết có kích thước nhỏ trong giao diện chứ không phải là toàn bộ window layout. Ví dụ, bạn có thể sử dụng WrapPanel để sắp xếp các buttons giống như một thanh toolbar.


Dưới đây là một ví dụ sử dụng WrapPanel. Nó chứa một số button với các kiểu align khác nhau:

<WrapPanel Margin="3">
   <Button VerticalAlignment="Top">Top Button</Button>
   <Button MinHeight="60">Tall Button 2</Button>
   <Button VerticalAlignment="Bottom">Bottom Button</Button>
   <Button>Stretch Button</Button>
   <Button VerticalAlignment="Center">Centered Button</Button>
</WrapPanel>  

Hình ảnh dưới đây thể hiện cách hiển thị các button này tùy theo kích thước của WrapPanel (ở đây cũng chính là kích thước của window). Ví dụ trên sử dụng giá trị mặc định của property Orientation, do đó các button được sắp xếp trên một hàng, mỗi button sẽ có chiều cao bằng với chiều cao của button to nhất. Các control khác có thể được sắp xếp theo kiểu khác tùy theo thuộc tính VerticalAlignment. Trong hình đầu tiên, các bạn có thể thấy các button này nằm trên cùng một hàng và tất cả đều được kéo dãn hoặc định vị tùy theo thuộc tính của nó. Còn ở hình thứ hai, một số button đã bị “đá” xuống hàng dưới. Bởi vì hàng thứ 2 không có button nào cao bất thường, do đó chiều cao của hàng này bằng với chiều cao tối thiểu của button. Như các bạn thấy, thuộc tính VerticalAlignment không có tác dụng trong hàng thứ 2 này.

The DockPanel

DockPanel là một loại contain layout rất thú vị. Nó kéo dãn các control ra đến các cạnh của nó. Hình ảnh cụ thể để miêu tả dockpanel chính là các thanh toolbars thường nằm ở top của các của số. Các thanh toolbar này thường được neo vào phần top của window. Nếu bạn dock một button vào phần trên của DockPanel, nó sẽ kéo dãn chiều rộng ra tối đa, nhưng chiều cao sẽ chỉ vừa đủ theo yêu cầu (phụ thuộc vào content và MinHeight Property). Còn nếu bạn dock button vào bên trái của DockPanel, chiều cao của button đó sẽ kéo dãn ra tối đa, còn chiều rộng sẽ chỉ rộng vừa đủ. Có thể bạn sẽ thắc mắc, làm sao chúng ta neo các element vào từng bên theo ý muốn? Ở đây, chúng ta sẽ sử dụng một loại attached property có tên là Dock, các giá trị của nó gồm có Left, Right, Top hoặc Button. Tất cả các element đặt trong DockPanel đều được set thuộc tính này một cách tự động.

Dưới đây là một ví dụ về việc sử dụng DockPanle:

<DockPanel LastChildFill="True">
   <Button DockPanel.Dock="Top">Top Button</Button>
   <Button DockPanel.Dock="Bottom">Bottom Button</Button>
   <Button DockPanel.Dock="Left">Left Button</Button>
   <Button DockPanel.Dock="Right">Right Button</Button>
   <Button>Remaining Space</Button>
</DockPanel>  

Ở đây, chúng ta set giá trị của Property LastChildFill thành true, như vậy toàn bộ không gian còn lại sẽ thuộc về element cuối cùng trong panel:

Rõ ràng, khi neo một control vào một bên nào đó thì thứ tự là một yếu tố rất quan trọng. Trong ví dụ trên, top button và bottom button có chiều rộng tối đa bởi vì nó được dock trước. Còn left button và right button được dock sau, do đó chúng chỉ có kích thước vừa với phần còn lại của window. Nếu thay đổi thứ tự này, left button và right button sẽ nhận chiều cao tối đa, và top và bottom button sẽ bị ngắn bớt đi.

Bạn cũng có thể dock các elememt vào cùng một phía. Trong trường hợp này, các element tự động sắp xếp liên tiếp nhau tùy theo side mà bạn đã set cho chúng. Bạn còn có thể sử dụng các thuộc tính như Margin, HorizontalAlignment và VerticalAlignment để thay đổi cách bố trí của nó theo ý muốn. Dưới đây là một ví dụ khác:

<DockPanel LastChildFill="True">
   <Button DockPanel.Dock="Top">A Stretched Top Button</Button>
   <Button DockPanel.Dock="Top" HorizontalAlignment="Center">
     A Centered Top Button</Button>
   <Button DockPanel.Dock="Top" HorizontalAlignment="Left">
     A Left-Aligned Top Button</Button>
   <Button DockPanel.Dock="Bottom">Bottom Button</Button>
   <Button DockPanel.Dock="Left">Left Button</Button>
   <Button DockPanel.Dock="Right">Right Button</Button>
   <Button>Remaining Space</Button>
</DockPanel>  

Kết quả:

Kết hợp sử dụng các loại Layout Container

StackPanel, WrapPanel và DockPanel ít khi được sử dụng một mình. Thay vào đó, nó thường dùng ở các vùng khác nhau trong giao diện của bạn. Ví dụ dưới đây sẽ mô tả cách sử dụng các loại panel lồng vào nhau để tạo ra một giao diện linh hoạt:

<DockPanel LastChildFill="True">
   <StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right"
    Orientation="Horizontal">
     <Button Margin="10,10,2,10" Padding="3">OK</Button>
     <Button Margin="2,10,10,10" Padding="3">Cancel</Button>
   </StackPanel>
   <TextBox DockPanel.Dock="Top" Margin="10">This is a test.</TextBox>
</DockPanel>  

 

Giả sử sau này bạn muốn thay đổi vị trí của nút OK và Cancel, bạn chỉ cần set lại giá trị của thuộc tính HorizontalAlignment như sau:

<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Center" ... >

Công việc rất đơn giản này lại trở thành bất khả thi nếu bạn sử dụng Windows Form trong .NET 1.x mà không phải viết bất kì dòng code nào.