Stackpanel là một trong số các loại layout container đơn giản nhất. Nó đơn giản sắp xếp các children element vào từng cột, hàng. Chúng ta sẽ cũng xem qua ví dụ về một cửa sổ dùng stackpanel có chứa 4 buttons bên trong:

Dưới đây là đoạn mã XAML của cửa sổ trên:

<Window x:Class="Layout.SimpleStack"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Layout" Height="223" Width="354"
    >
    <StackPanel>
       <Label>A Button Stack</Label>
       <Button>Button 1</Button>
       <Button>Button 2</Button>
       <Button>Button 3</Button>
       <Button>Button 4</Button>
    </StackPanel>
</Window> 

Mặc định, StackPanel sắp xếp các thành phần theo thứ tự từ trên xuống dưới, mỗi element sẽ cao vừa đủ để hiển thị nội dung của nó. Trong ví dụ này, label và các button đều cao vừa đủ để có thể hiển thị đoạn text bên trong. Nếu bạn nới rộng window, StackPanel cũng sẽ rộng ra theo, và các button cũng sẽ tự động kéo dãn ra để vừa với stackpanel.

StackPanel cũng có thể dùng để sắp xếp các phần tử theo chiều ngang bằng cách thiết lập giá trị cho property Orientation:

<StackPanel Orientation="Horizontal">

Lúc này, các element sẽ có độ rộng nhỏ nhất (đủ để hiển thị toàn bộ nội dung bên trong) và được kéo dãn chiều cao ra bằng với chiều cao của panel. Tuy nhiên, một vài element có thể sẽ không thể hiển thị hết tùy thuộc vào kích thước của cửa sổ (xem hình bên dưới):

Rõ ràng, việc này không mang lại sự tiện lợi cho các ứng dụng. Tuy nhiên, bạn có thể điều chỉnh StackPanel cũng như các loại layout container khác để hiển thị theo ý muốn của bạn bằng các dùng các layout properties.

Layout properties

Thực tế, các loại layout panel đều phối hợp cùng với các thành phần con của nó thông qua một vài layout properties, các property này được liệt kê như bên dưới:

Name

Description

HorizontalAlignment

Sắp xếp các element theo chiều ngang nếu có khoảng trống. Gồm các giá trị Center, Left, Right, Stretch

VerticalAlignment

Tương tự như horizontalalignment nhưng sẽ theo chiều dọc. Gồm các giá trị như Center, Top, Botton, Stretch

Margin

Thêm các khoảng trống bên ngoài element. Margin property là một thể hiện của struct System.Windows.Thickness, gồm có 4 thành phần tương ứng với 4 cạnh của element: top, bottom, left, right.

MinWidth và MinHeight

Chiều cao và chiều rộng tối thiểu của element. Nếu một thành phần nào đó quá to so với layout container, nó sẽ bị cắt bớt để vừa với container.

MaxWidth và MaxHeight

Chiều cao và chiều rộng tối đa của element. Nếu container có nhiều khoảng trống hơn, các element cũng sẽ không bị nới rộng ra quá giới hạn này, kể cả khi HorizontalAlignment và VerticalAlignment property được gán là Stretch

Width và Height

Cố định kích thước của element. Thiết lập này sẽ override giá trị Stretch của HorizontalAlignment hoặc VerticalAlignment property. Tuy nhiên, giá trị của thuộc tính này sẽ không được chấp nhận nếu nó vượt quá giá trị của các thuộc tính Min và Max đã đề cập ở trên.

 

Alignment

Để hiểu rõ cách làm việc của các property này, chúng ta sẽ xem qua một ví dụ khác về StackPanel. Trong ví dụ này, ta dùng StackPanel hướng theo chiều dọc, do đó VerticalAlignment property sẽ không có tác dụng bởi vì mỗi element chỉ được cung cấp chiều cao mà nó yêu cầu chứ không hơn. Tuy nhiên, HorizontalAlignment thì khác, nó sẽ quy định nơi đặt vị trí của các element theo từng hàng. Ban đầu, mặc định của thuộc tính HorizontalAlignment là Left cho Label control, và đối với Button là Stretch. Điều này giải thích tại sao mọi button đều có chiều rộng bằng với chiều rộng của panel. Tất nhiên, bạn cũng có thể thay đổi các chi tiết này:

<StackPanel>
    <Label HorizontalAlignment="Center">A Button Stack</Label>
    <Button HorizontalAlignment="Left">Button 1</Button>
    <Button HorizontalAlignment="Right">Button 2</Button>
    <Button>Button 3</Button>
    <Button>Button 4</Button>
</StackPanel>  

Hình ảnh dưới đây chính là kết quả của đoạn mã trên. Nếu bạn thay đổi kích thước của window, bạn sẽ thấy lable vẫn nằm ở chính giữa, 2 button đầu tiên sẽ luôn dính vào 2 cạnh.


Note:

StackPanel cũng có thuộc tính HorizontalAlignment và VerticalAlignment của nó. Mặc định, cả 2 đều được set thành Stretch, nhờ đó, StackPanel luôn luôn fill toàn bộ container của nó. Trong ví dụ này, container của StackPanel chính là window, và như bạn thấy, kích thước của nó trải ra vừa với window.


Margin

Một window được thiết kế đẹp sẽ không chỉ có các element – nó còn bao gồm các khoảng trống giữa các element. Để thiết lập các khoảng trống này và làm cho ví dụ StackPanel bớt “xấu xí”, bạn có thể thay đổi giá trị của margin property. Khi thiết lập thuộc tính cho property này, bạn có thể chỉ cần set một giá trị duy nhất cho cả 4 cạnh, như thế này:

<Button Margin="5">Button 3</Button>

Hoặc bạn cũng có thể thiết lập giá trị của mỗi cạnh khác nhau theo thứ tự left, top, right, botton (lưu ý là thứ tự này khác với thứ tự margin trong CSS):

<Button Margin="5,10,5,10">Button 3</Button>

Nếu bạn thiết lập margin property bằng mã C#, bạn cần phải sử dụng Thickness structure:

cmd.Margin = new Thickness(5);

Việc sử dụng thuộc tính margin hợp lí cũng xem như một nghệ thuật bởi vì bạn cần phải quan tâm đến thuộc tính margin của một control sẽ anh hưởng như thế nào đến một control khác. Ví dụ, nếu bạn có 2 button sắp theo thứ tự hàng dọc, ở trên cùng mỗi button sẽ có một khoảng cách là 5, và dưới cùng mỗi button cũng vậy, như vậy bạn có tổng cộng 10 đơn vị khoảng cách giữa 2 button.

Chúng ta nên tránh việc thiết lập mỗi cạnh của margin property một giá trị khác nhau. Trong ví dụ dưới đây, chúng ta sử dụng cùng một giá trị margin cho mọi button và trên cả stackpanel:

<StackPanel Margin="3">
   <Label Margin="3" HorizontalAlignment="Center">
    A Button Stack</Label>
   <Button Margin="3" HorizontalAlignment="Left">Button 1</Button>
   <Button Margin="3" HorizontalAlignment="Right">Button 2</Button>
   <Button Margin="3">Button 3</Button>
   <Button Margin="3">Button 4</Button>
</StackPanel>  

Bằng cách này, tổng khoảng cách giữa 2 button bằng với tổng khoảng cách giữa cạnh button tới cạnh window:

Hình ảnh dưới đây sẽ giúp bạn hiểu rõ hơn về thuộc tính Margin:

[To be continued…]