WPF提供了丰富而灵活的布局机制,我们利用一些工具可以很方便的控制元素的布局格式。
1. 布局基础:
WPF提供了一组面板(panel)用于控制布局,每个面板都有自己的一些特性,你可以根据需要选择面板,或是组合或是嵌套面板从而灵活控制你的布局。
StackPanel:横向或是竖向排列子控件,常用于小范围排版场合
WrapPanel:类似于StackPanel,将子控件从左到右排列,不同的是当横向空间不够时,他会自动换到下一行。
DockPanel:类似于Winform中的Dock属性,将子控件贴在某个方向上。
Grid :将子控件排列于行和列中,可以灵活的定义行列的宽度和跨度
UniformGrid:类似于Grid,不过每个单元格的大小是相同的.
Canvas:以坐标的方式控制子控件的位置,唯一一种可以完全控制位置的方式。
2. StackPanel布局:
StackPanle就是简单的将内容横向或是竖向排成一列,通过Orientation="Horizontal"属性设置,默认是vertical竖向排列。例如:
<StackPanel Background="#ECE9D8">
<TextBlock Margin="3">Look for:</TextBlock>
<ComboBox Margin="3"/>
<TextBlock Margin="3">Filtered by:</TextBlock>
<ComboBox Margin="3"/>
<Button Margin="3,5">Search</Button>
<CheckBox Margin="3">Search in titles only</CheckBox>
<CheckBox Margin="3">Match related words</CheckBox>
<CheckBox Margin="3">Search in previous results</CheckBox>
<CheckBox Margin="3">Highlight search hits (in topics)</CheckBox>
</StackPanel>
产生效果如图:
其中Margin类似于Css中的margin元素,设置元素的浮动情况,是公共布局属性的一部分,在后面会提到。在上面一张效果图中我们可以看到TextBlock控件和CheckBox控件都是很自然的显示在一行,但是Search按钮却显的很宽,非常的不好看,这是因为默认情况下StackPanel是将所有子控件都是和Panel同宽或是同高的,这里所有子控件的宽度都是和StackPanel同宽的。为了控制子控件的宽度或高度,可以设置HorizontalAlignment和VerticalAlignment属性,当竖向排版时设置HorizontalAlignment,可设置为left,right,center和Stretch,横向排版时设置VerticalAlignment属性,可设置为Top,Buttom,Center和Stretch,本例中设置HorizontalAlignment为Left:
<Button Margin="3,5" HorizontalAlignment="Left">Search</Button>
按钮就会保持原来自己的宽度,然后左对齐到StackPanel中,如果设置Center或right同样,会对齐到中间或是右边。
横向排版例子:
<StackPanel Orientation="Horizontal">
<TextBlock>This is some text</TextBlock>
<Button>Button</Button>
<Button>Button (different one)</Button>
<CheckBox>Check it out</CheckBox>
<TextBlock>More text</TextBlock>
</StackPanel>
StackPanel在内容大于Panel的时候处理不够灵活,通常会阶段多出的控件,相比而言,WrapPanel就要聪明很多。
3. WrapPanel布局:
WrapPanel和StackPanel非常类似,只有在子控件超出Panel范围时有所不同,WrapPanel会换行,就像在Word里面打字一样,当字数超过一行的范围时就会自动跳转到下一行:
<WrapPanel Background="Beige">
<Button>One</Button>
<Button>Two</Button>
<Button>Three</Button>
<Button>Four</Button>
<Button>Five</Button>
<Button>Six</Button>
<Button>Seven</Button>
<Button>Eight</Button>
</WrapPanel>
WrapPanel同样有Orientation属性,用于设置子控件的排列方向。
WrapPanel和StackPanel在小规模排版中非常常见,但是当你在复杂的场合时,可能需要更强大的排版工具,下面会一一介绍。
4. DockPanel布局:
DockPanel在全局布局中非常有用,它通常用于整个界面的划分,然后通过其他布局控件来做细节的布局。
DockPanel将子控件“贴”在某个边上,如果多个子控件同时设置到一个方向,默认情况下,先设置的越靠近边界,后面的子控件占用剩下的空间。我们先看个例子:
<DockPanel>
<Button DockPanel.Dock="Top">Top</Button>
<Button DockPanel.Dock="Bottom">Bottom</Button>
<Button DockPanel.Dock="Left">Left</Button>
<Button DockPanel.Dock="Right">Right</Button>
<Button>Fill</Button>
</DockPanel>
这个例子使用了DockPanel.Dock,这其实是属于XAML中的Attached Properties(附加属性)语法。
关于附加属性:WPF中有些需求像DockPanel就是要将某个子控件排列到某个边上,处理的方式最自然的就是使用一个基类拥有一个Dock属性,然后DockPanel继承自这个基类,通常情况下可以解决这个问题,但是对于其他Panel来说却有些凌乱,因为其他panel不需要dock属性, 而且这个方案还缺乏灵活性,假如你需要创建一个新的自定义panel需要实现新的布局需求时,你需要添加新的属性来满足你的需求。XAML语法中的附加属性就是解决这个问题的方案,附件属性可以让控件元素的属性附加另外的元素。DockPanel定义了Dock属性并且可以被任何子控件附件,这样他的任何子元素都可以设置自己的Dock属性。
<DockPanel>
<Button DockPanel.Dock="Left">Left</Button>
<Button DockPanel.Dock="Right">Right</Button>
<Button DockPanel.Dock="Top">Top</Button>
<Button DockPanel.Dock="Bottom">Bottom</Button>
<Button>Fill</Button>
</DockPanel>
DockPanel里的内容不会重叠,后面的控件只会占据余下的空间,默认情况下,最后一个控件将占据所有剩下的控件,例如图中的fill控件,但是也可以设置LastChildFill属性为false(默认为true)让他保持自己的大小,默认会排列在左边,从而留下中间的空间。
设置为top或bottom的控件宽度会填充到所有空间,例如上图,top控件会填充所有能填充的宽度,直到left和right控件,但是他们的高度是根据内容决定的,如果一行字符,高度就是一个字符,如果存在两行字符,高度就会变大。同样设置为left和right的控件在高度是固定的,填充全部高度,但是宽度是根据内容决定的。
DockPanel在全局规划中非常有用,例如你需要设计一个菜单栏或是工具栏,那么就在top放置一个DockPanel作为菜单或是工具栏,而剩下的由其他控件填充。