WPF之路-常用布局控件二
Grid容器
Grid控件作为WPF中最为重要的布容器
调整行与列
通过Grid.RowDefinitions来定义行,Grid.ColumnDefinitions来定义列
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<!--Grid.RowDefinitions定义行-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition><!--一行-->
<RowDefinition></RowDefinition><!--一行-->
</Grid.RowDefinitions>
<!--Grid.ColumnDefinitions定义列-->
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition><!--一列-->
<ColumnDefinition></ColumnDefinition><!--一列-->
</Grid.ColumnDefinitions>
</Grid>
</Window>
上例中定义了两行两列,因此Grid被分割成了四个部分
布局舍入
Grid的 宽度和高度设置的三种方法:
- 指定数值 如: Width = "50" ,不建议使用此方式
- 等比例设置: Width="*" Width = "2*" Width = "3*" 这样的话,三个单元则以1:2:3 比例设置大小
<!--Grid.ColumnDefinitions定义列-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="2*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="3*"></ColumnDefinition><!--一列-->
</Grid.ColumnDefinitions>
</Grid>
- 自适应: Width = “Auto” 单元格适应内部控件大小 也就是说,元素的大小多大,分割的部分就会自动变成多大
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<!--Grid.RowDefinitions定义行-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition><!--一行-->
<RowDefinition Height="Auto"></RowDefinition><!--一行-->
</Grid.RowDefinitions>
<!--Grid.ColumnDefinitions定义列-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="2*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="3*"></ColumnDefinition><!--一列-->
</Grid.ColumnDefinitions>
<!--在第二行第一列上加一个按钮-->
<Button Grid.Column="0" Grid.Row="1">你好</Button>
</Grid>
</Window>
当Grid的大小按比例模式进行分割时,可能某一部分的大小不是一个整数,此时如果在该部分加一个整数大小像素的图片,就会变得模糊,这是由于WPF的混合锯齿是的最小单元格的界面显示模糊,为了解决这种情况,则需要设置Grid 的UseLayoutRounding 属性,以增加抗锯齿效果
<Grid UseLayoutRounding="True">
将元素跨行或跨列安放
ColumnSpan 属性表示跨列 RowSpan 属性表示跨行
示例代码<Button Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2">你好</Button>,如下图
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid UseLayoutRounding="True">
<!--Grid.RowDefinitions定义行-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition><!--一行-->
<RowDefinition ></RowDefinition><!--一行-->
</Grid.RowDefinitions>
<!--Grid.ColumnDefinitions定义列-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="2*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="3*"></ColumnDefinition><!--一列-->
</Grid.ColumnDefinitions>
<!--在第二行第一列上加一个按钮-->
<Button Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2">你好</Button>
</Grid>
</Window>
分割容器
GridSplitter 控件就是用来分割Grid控件的,必须放在Grid里面
示例代码<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" Grid.RowSpan="3" HorizontalAlignment ="Left" Width="5"/>,如下图
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid UseLayoutRounding="True">
<!--Grid.RowDefinitions定义行-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition><!--一行-->
<RowDefinition ></RowDefinition><!--一行-->
</Grid.RowDefinitions>
<!--Grid.ColumnDefinitions定义列-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="*"></ColumnDefinition><!--一列-->
<ColumnDefinition Width="*"></ColumnDefinition><!--一列-->
</Grid.ColumnDefinitions>
<!--在第二行第一列上加一个按钮-->
<Button Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="1">你好</Button>
<!--添加侵害容器-->
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" Grid.RowSpan="2" HorizontalAlignment ="Left" Width="5"/>
</Grid>
</Window>
共享尺寸组
SharedSizeGroup属性允许相同名的元素具有等大的效果
需要在父容器 设置属性 Grid.IsSharedSizeScope="True"
示例如下:
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<!--定义一个父容器,Grid.IsSharedSizeScope="True"是必须的-->
<Grid ShowGridLines="True" Grid.IsSharedSizeScope="True">
<!--在父容器中定义了两行-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<!--在父容器的第一行定义一个子容器-->
<Grid ShowGridLines="True" Name="grid_1" Background="blue" Grid.Row="0">
<Grid.ColumnDefinitions>
<!--第一个子容器的第一列指定了SharedSizeGroup属性-->
<ColumnDefinition Width="50" SharedSizeGroup="A" ></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
<!--在父容器的第二行定义一个子容器-->
<Grid ShowGridLines="True" Name="grid_2" Background="Green" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<!--第二个子容器的第二列指定了SharedSizeGroup属性-->
<ColumnDefinition SharedSizeGroup="A" ></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</Grid>
</Window>
Canvas面板
Canvas面板是基于坐标的布局容器;Canvas中的子元素的位置是需要显性设定的固定位置,通过Canvas的属性Left/Rigth/Top/Bottom来设置子元素相的位置
下例是一个距离下边界20、左边界20位置的一个按钮
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas>
<Button Canvas.Bottom="20" Canvas.Left="20">Hello</Button>
</Canvas>
</Window>
上例描述的是元素在Canvas容器中的二维坐标,即X-Y坐标,还可以定义元素第三维坐标,即Z坐标f
下例中定义了三个图形,一个圆,三个矩形,它们之间的重叠是按默认的顺序叠加的(未定义过Z坐标的,其Z坐标是0),可以通过设定Canvas.ZIndex属性值或Panel.ZIndex来调整元素的重叠顺序,值越大的越靠前
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas>
<Ellipse Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
<Rectangle Canvas.ZIndex="3" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
<Rectangle Panel.ZIndex="2" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
<Rectangle Panel.ZIndex="1" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
</Canvas>
</Window>
调整矩形的顺序,如下:
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas>
<Ellipse Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
<Rectangle Canvas.ZIndex="1" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
<Rectangle Panel.ZIndex="2" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
<Rectangle Panel.ZIndex="3" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
</Canvas>
</Window>
InkCavas元素
InkCavas是一个画图控件,它允许在它之上加载其它控件,比如加载一个按钮;可以通过InkCanvas的Right/Left/Bottom/Top属性来指定元素的位置
Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<InkCanvas>
<Button Content="Hello" InkCanvas.Bottom="50" InkCanvas.Left="30" />
</InkCanvas>
</Window>
运行程序后,可发现,当鼠标移动到InkCanvas区域时,鼠标会变成一个黑点,按下鼠标左键移动会画出线条
InkCanvas的EditingMode的属性可根据不同的值,设定图画的不同功能
EditingMode="EraseByPoint"表示鼠标变成一个可擦除点的工具
EditingMode="EraseByStroke"表示鼠标变成一个可橡皮擦
EditingMode="GestureOnly"表示按下鼠标可画线,鼠标松开后所画的线条将消失
EditingMode="Ink"表示按下鼠标可画出墨线,本属性值是默认的
EditingMode="InkAndGesture"与Ink功能类似,但同时可以识别用户的手势
EditingMode="None"表示没有任何反应
EditingMode="Select" 表示可以选择一个元素,可以移动它、删除它,改变形状等
下面通过将这些属性动态的加载到下拉框中,通过选择不同的属性值来体验不同的画图效果
<Window x:Class="WPF_Code.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<InkCanvas Grid.Row="1" Name="incas">
<Button Content="Hello" InkCanvas.Bottom="50" InkCanvas.Left="30" />
</InkCanvas>
<ComboBox Grid.Row="0" Name="cmb_model" SelectionChanged="cmb_model_SelectionChanged" />
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
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 WPF_Code
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
public MainWindow()
InitializeComponent();
/// <summary>
/// 下拉框选择事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cmb_model_SelectionChanged(object sender, SelectionChangedEventArgs e)
//将InkCavas的EditingMode属性设置为选择后的属性
//需要将SelectedItem强转成InkCanvasEditingMode类型
this.incas.EditingMode = (InkCanvasEditingMode)this.cmb_model.SelectedItem;
/// <summary>
/// 窗体加载事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Loaded(object sender, RoutedEventArgs e)
//Enum.GetValues用于检索指定枚举中常数值的数组
//typeof用于获取类型的 System.Type 对象
foreach (InkCanvasEditingMode item in Enum.GetValues(typeof(InkCanvasEditingMode)))
//循环将InkCanvasEditingMode枚举值添加到下拉框中
this.cmb_model.Items.Add(item);