WPF当中有许多的布局容器控件,例如<Grid>、<StackPanel>、<WrapPanel>、<DockPanel>、<UniformGrid>。接下来分别介绍一下各个布局容器控件。
布局基础
Grid
<Grid><Grid.RowDefinitions><RowDefinition Height="2*"/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="2*"/><ColumnDefinition/></Grid.ColumnDefinitions><Border Grid.Row="0" Grid.Column="0" Background="Red"/><Border Grid.Row="0" Grid.Column="1" Background="Yellow"/><Border Grid.Row="1" Grid.Column="0" Background="Blue"/><Border Grid.Row="1" Grid.Column="1" Background="Green"/>
</Grid>
Grid中的元素还可以跨行和跨列:
StackPanel
StackPanel默认水平排列,具有 Orientation=""属性可以改变排列方向。
WrapPanel
WrapPanel默认水平排列,也具有 Orientation=""属性可以改变排列方向。
DockPanel
DockPanel具有停靠的功能,位于DockPanel中的元素,可以设置它的方向。
UniformGrid
这个容器最大的作用就是在有限的空间里面均分剩余空间。
下面对一个页面进行布局模拟练习:
<Grid><Grid.RowDefinitions><RowDefinition Height="80"/><RowDefinition/></Grid.RowDefinitions><Border Background="#FFECF1"/><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="200"/><ColumnDefinition/></Grid.ColumnDefinitions><Border Background="#FF7F24"/><Grid Grid.Column="1" Margin="5"><Grid.RowDefinitions><RowDefinition Height="100"/><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid Grid.Row="0"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Border Margin="5" Grid.Column="0" Background="#1b1c1d"/><Border Margin="5" Grid.Column="1" Background="#2AC864"/><Border Margin="5" Grid.Column="2" Background="#1b1c1d"/><Border Margin="5" Grid.Column="3" Background="#F85A54"/><Border Margin="5" Grid.Column="4" Background="#1b1c1d"/></Grid><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="1.5*"/><ColumnDefinition/></Grid.ColumnDefinitions><Border Margin="5" Grid.Column="0" Background="#1b1c1d"/><Border Margin="5" Grid.Column="1" Background="#2AC864"/></Grid><Grid Grid.Row="2"><Grid.ColumnDefinitions><ColumnDefinition Width="1.5*"/><ColumnDefinition/></Grid.ColumnDefinitions><Border Margin="5" Grid.Column="0" Background="#1b1c1d"/><Border Margin="5" Grid.Column="1" Background="#F85A54"/></Grid></Grid></Grid>
</Grid>
样式基础
样式负责修饰元素的外观以及行为,可以在样式中定义不同类型元素的属性值集合。
<Window.Resources><Style x:Key="BaseStyle" TargetType="Button"><Setter Property="FontSize" Value="18"/><Setter Property="Foreground" Value="White"/><Setter Property="Background" Value="Red"/></Style><Style x:Key="BottonStyle" TargetType="Button" BasedOn="{StaticResource BaseStyle}"><Setter Property="Content" Value="Botton1"/></Style>
</Window.Resources>
<Grid><StackPanel><Button Background="Blue" Style="{StaticResource BottonStyle}"/><Button Style="{StaticResource BottonStyle}"/><Button Style="{StaticResource BottonStyle}"/></StackPanel>
</Grid>
数据模板
<Grid><ListBox x:Name="list"><ListBoxItem><StackPanel Orientation="Horizontal"><Border Width="10" Height="10" Background="Red"/><TextBlock Margin="10,0" Text="Red"/></StackPanel></ListBoxItem><ListBoxItem><StackPanel Orientation="Horizontal"><Border Width="10" Height="10" Background="Blue"/><TextBlock Margin="10,0" Text="Red"/></StackPanel></ListBoxItem><ListBoxItem><StackPanel Orientation="Horizontal"><Border Width="10" Height="10" Background="Green"/><TextBlock Margin="10,0" Text="Red"/></StackPanel></ListBoxItem></ListBox>
</Grid>
可以看到,这里每一项的构造都是完全相同的,唯一不同的就是它们的数据,因此可以将它抽离出来作为一个模板。
<Grid><ListBox x:Name="list"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><Border Width="10" Height="10" Background="{Binding Code}"/><TextBlock Margin="10,0" Text="{Binding Name}"/></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox>
</Grid>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;namespace WpfApp4 {/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window {public MainWindow() {InitializeComponent();List<Color> test = new List<Color>();test.Add(new Color() { Code = "#FFB6C1", Name = "浅粉红" });test.Add(new Color() { Code = "#FFC0CB", Name = "粉红" });test.Add(new Color() { Code = "#DC143C", Name = "猩红" });test.Add(new Color() { Code = "#FFF0F5", Name = "脸红的淡紫色" });//LightPink 浅粉红 #FFB6C1 255,182,193//Pink 粉红 #FFC0CB 255,192,203//Crimson 猩红 #DC143C 220,20,60//LavenderBlush 脸红的淡紫色 #FFF0F5 255,240,245list.ItemsSource = test;}public class Color {public string Code { get; set; }public string Name { get; set; }}}
}
由此就可以看到DataTemplate的作用。继续编写例子:
<Grid><DataGrid x:Name = "grid" AutoGenerateColumns="False" CanUserAddRows="False"><DataGrid.Columns><DataGridTextColumn Header="Code" Binding="{Binding Code}"/><DataGridTextColumn Header="Name" Binding="{Binding Name}"/><DataGridTemplateColumn Header="操作"><DataGridTemplateColumn.CellTemplate><DataTemplate><StackPanel Orientation="Horizontal"><Button Content="删除" /><Button Content="复制" /><Button Content="保存" /></StackPanel></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn></DataGrid.Columns></DataGrid>
</Grid>
灵活地使用DataTemplate数据模块,对后续开发有很重要的帮助,当然DataTemplate的应用不止于此,后续还会介绍到。
绑定
使用绑定可以使得控件与控件之间建立一种绑定关系,可以不再为此编写大量的代码来维持。
<Grid><StackPanel><Slider x:Name="slider" Margin="5" ValueChanged="Slider_ValueChanged"/><TextBox x:Name="textbox1" Margin="5" Height="30" TextChanged="textbox1_TextChanged"/><TextBox x:Name="textbox2" Margin="5" Height="30"/><TextBox x:Name="textbox3" Margin="5" Height="30"/></StackPanel>
</Grid>
namespace WpfApp5 {/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window {public MainWindow() {InitializeComponent();}private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {textbox1.Text = slider.Value.ToString();textbox2.Text = slider.Value.ToString();textbox3.Text = slider.Value.ToString();}private void textbox1_TextChanged(object sender, TextChangedEventArgs e) {if (double.TryParse(textbox1.Text, out double result))slider.Value = result;}}
}
此时代码实现了拖动滑块,下方三个框里的数据会同步变化。对下方任意一个框里的数据进行修改,上方滑块的位置也会同步变化。为了实现这个功能,代码变得特别的冗余,可以使用绑定来简化。
<Grid><StackPanel><Slider x:Name="slider" Margin="5"/><TextBox Text="{Binding ElementName=slider,Path=Value}" x:Name="textbox1" Margin="5" Height="30"/><TextBox Text="{Binding ElementName=slider,Path=Value}" x:Name="textbox2" Margin="5" Height="30"/><TextBox Text="{Binding ElementName=slider,Path=Value}" x:Name="textbox3" Margin="5" Height="30"/></StackPanel>
</Grid>
此时就不需要具体的实现代码了,使用绑定就可以完成两个控件的双向绑定。