参考书籍《深入浅出WPF》,原书1-5章节。
新建WPF项目
标记扩展
使用Binding类的实例将TextBox的Text属性依赖在Slider的Value上
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Wpf1_test_8_17.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<StackPanel Background="LightSlateGray">
<!-- 标记扩展-->
<TextBox Text="{Binding ElementName=slider1, Path=Value, Mode=OneWay}" Margin="5"/>
<Slider x:Name="slider1" Margin="5"/>
</StackPanel>
</Grid>
</Window>
事件处理器
代码后置
默认情况下,控件与代码是分开的。即代码后置。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Wpf1_test_8_17.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<StackPanel Background="LightSlateGray">
<!--添加控件尺寸大小,否则默认是一个小点-->
<Button x:Name="button1" Width="20" Height="20" Click="click_1"/>
</StackPanel>
</Grid>
</Window>
private void click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show("hello WPF!");
}
Button 控件的行高和列宽都为0,控件显示为一个点
代码前置
使用 <x:Code>和<![CDATA[将后置的代码前移到XAML中
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Wpf1_test_8_17.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<StackPanel Background="LightSlateGray">
<!--添加控件尺寸大小,否则默认是一个小点-->
<Button x:Name="button1" Width="20" Height="20" Click="click_1"/>
</StackPanel>
</Grid>
<x:Code>
<![CDATA[
private void click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show("hello WPF!");
}
]]>
</x:Code>
</Window>
x名称空间中标记扩展:x:Type
1、在添加一个Button派生类
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 Wpf1_test_8_17
{
class MYbutton:Button //创建Button的派生类
{
public Type UserWindwoTpye { get; set; }
protected override void OnClick()
{
base.OnClick();
Window win = Activator.CreateInstance(this.UserWindwoTpye) as Window;
if(win!=null)
{
win.ShowDialog();
}
}
}
}
这里重写了基类的Button方法,除了可以像基类那样触发click()事件外,还会使用UserWindwoTpye所存储的类型创建一个实例。如果这个实例是window类那么就把窗体显示出来。
2、添加一个名为"Window1"的Window派生类,添加3个TextBox和1个Button空间如下:
<Window x:Class="Wpf1_test_8_17.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel Background="LightBlue">
<TextBox Margin="5"/>
<TextBox Margin="5"/>
<TextBox Margin="5"/>
<Button Content="OK" Margin="5"/>
</StackPanel>
</Window>
3、把自定义按钮添加到主窗口中,并且把Window1作为一种数据类型赋值给MYbutton 的UserWindwoTpye
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Wpf1_test_8_17.MainWindow"
xmlns:local="clr-namespace:Wpf1_test_8_17"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:MYbutton Content="show" UserWindwoTpye="{x:Type TypeName=local:Window1}" Margin="5"/>
</StackPanel>
</Window>
4、程序运行效果:
Headered Content Control族
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<GroupBox Margin="10" BorderBrush="Gray">
<GroupBox.Header>
<Image Source="E:\Test_Img_Video\icoSet\plant\Bnn12.png"/>
</GroupBox.Header>
<TextBlock TextWrapping="WrapWithOverflow" Margin="10"
FontSize="40" Text="一棵树、一朵花"/>
</GroupBox>
</Grid>
</Window>
ItemsControl族
自动使用条目容器对提交的内容进行包装,允许程序员提交各种数据类型集合。
可以显示元素丰富的条目:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Width="100" Height="100" Margin="5">
<CheckBox x:Name="checkbox_Tinker" Content="Tinker"/>
<Button x:Name="button_bell" Content="bell" Click="button_bell_click"/>
</ListBox>
</Grid>
</Window>
private void button_bell_click(object sender, RoutedEventArgs e)
{
MessageBox.Show("clicked!");
}
动态后台数据通过ItemsControl显示:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox x:Name="listBoxEmployee" Width="100" Height="100" Margin="5"/>
</Grid>
</Window>
namespace WpfApplication1_8_18
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public class Empolyee
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Empolyee> employee_list = new List<Empolyee>()
{
new Empolyee() { id = 1, name = "A", age = 1 },
new Empolyee() { id = 2, name = "B", age = 2 },
new Empolyee() { id = 3, name = "C", age = 3 }, //这里是,
}; //注意这里是//
this.listBoxEmployee.DisplayMemberPath = "name";//显示每条数据的那个属性
this.listBoxEmployee.SelectedValuePath = "id";//与selectValue配合使用,当一个Item被选中时,返回的是什么值
this.listBoxEmployee.ItemsSource = employee_list;
}
}
布局元素Grid
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
</Window>
效果:显示4列
在XAML中静态添加,4行3列的Grid显示效果:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</Window>
在C#中动态添加:
XAML中定义一个名为"Grid1"的Grid控件,窗体"MainWindow"添加事件Loaded=“MainWin_loaded”,在此事件中动态添加布局
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="MainWindow" Height="350" Width="525" Loaded="MainWin_loaded">
<Grid x:Name="Grid1" Width="200" Height="200">
</Grid>
</Window>
在窗体的Loaded事件中动态添加:
namespace WpfApplication1_8_18
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//写在这里没有用
}
private void MainWin_loaded(object sender, RoutedEventArgs e) //代码添加在窗体的load事件中
{
//动态添加Grid行:4行
this.Grid1.ColumnDefinitions.Add(new ColumnDefinition());
this.Grid1.ColumnDefinitions.Add(new ColumnDefinition());
this.Grid1.ColumnDefinitions.Add(new ColumnDefinition());
this.Grid1.ColumnDefinitions.Add(new ColumnDefinition());
//动态添加Grid列:3列
this.Grid1.RowDefinitions.Add(new RowDefinition());
this.Grid1.RowDefinitions.Add(new RowDefinition());
this.Grid1.RowDefinitions.Add(new RowDefinition());
//少了show则不会显示
this.Grid1.ShowGridLines = true;
}
}
}
Grid使用相对值
计算过程:150-25-25=100px 100px/(2+1+2)=20px =比例系数
这三行像素值:220=40px 120=20px 2*20=40px
Grid布局实例
按下图所示尺寸要求进行布局:
不要用Height+Width+Margin的方式进行布局,会使程序的可读性变差。正确的方法是使用Grid进行布局。
布局的设计预览如下:
<Window x:Class="WpfApplication1_8_18.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="240" Width="400">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" MinWidth="120"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/><!--"提交"-->
<ColumnDefinition Width="4"/><!--按钮间缝隙-->
<ColumnDefinition Width="80"/><!--"清除"-->
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="4"/>
<RowDefinition Height="*"/><!--占据全部剩余空间-->
<RowDefinition Height="4"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
</Grid>
</Window>
下一步,把标题填进去。其中文字内容使用了TextBlock ,输入框使用了TextBox ,其设置格式如下:
<TextBlock Text="请选择您的部门并留言:" Grid.Column="0" Grid.Row="0" VerticalAlignment="Center"/>
<TextBox Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="5" BorderBrush="Black"/>
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="留言板" Height="240" Width="400" >
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" MinWidth="120"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="4"/>
<RowDefinition Height="*"/>
<RowDefinition Height="4"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<TextBlock Text="请选择您的部门并留言:" Grid.Column="0" Grid.Row="0"/>
<ComboBox Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="4"/>
<Button Content="提交" Grid.Column="2" Grid.Row="4"/>
<Button Content="清除" Grid.Column="4" Grid.Row="4"/>
<TextBox Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="5" BorderBrush="Black"/>
</Grid>
</Window>
最终的效果图:
StackPanel
该控件最重要的功能是移除其中元素后会自动补齐。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="选择题" Height="190" Width="300" >
<Grid>
<GroupBox Header="请选择其中一个选项:" Margin="5" BorderBrush="Black">
<StackPanel Margin="5">
<CheckBox Content="A. 大漠孤烟直"/>
<CheckBox Content="B. 长河落日圆"/>
<CheckBox Content="C. 独向中庭待明月"/>
<CheckBox Content="D. 一身清露泄金波"/>
<CheckBox Content="E. 梨花满地不开门"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="清空" Width="60" Margin="5"/>
<Button Content="确定" Width="60" Margin="5"/>
</StackPanel>
</StackPanel>
</GroupBox>
</Grid>
</Window>
Canvas画布
大多数情况下,使用Grid和StackPanel使元素产生更简洁的布局而不能滥用Canvas。Canvas适用场合:
- 一经设计基本不再改动的小型布局(如图标)
- 艺术性比较强的布局
- 大量使用横纵坐标进行绝对点定位的布局
- 依赖于横纵坐标的动画
示例:用Canvas代替Grid设计登陆窗口,除非确定该登陆窗口布局不再改变且窗体尺寸固定,否则用Grid进行布局弹性好一些。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="登陆" Height="140" Width="300" >
<Canvas>
<TextBlock Text="用户名:" Canvas.Left="12" Canvas.Top="12"/>
<TextBox Height="23" Width="200" BorderBrush="Black" Canvas.Left="66" Canvas.Top="9"/>
<TextBlock Text="密码:" Canvas.Left="12" Canvas.Top="41"/>
<TextBox Height="23" Width="200" BorderBrush="Black" Canvas.Left="66" Canvas.Top="38"/>
<Button Content="确定" Width="80" Height="22" Canvas.Left="100" Canvas.Top="70"/>
<Button Content="清除" Width="80" Height="22" Canvas.Left="186" Canvas.Top="70"/>
</Canvas>
</Window>
DockPanel
其Dock属性在上、下、左、右四个方向上累积和切分DockPanel里剩余空间。
LastChildFill默认为True,最后一个元素会充满剩余空间。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="windows1" Height="300" Width="400" >
<Grid>
<DockPanel>
<TextBox DockPanel.Dock="Top" Height="25" BorderBrush="Black"/>
<TextBox DockPanel.Dock="Left" Width="150" BorderBrush="Black"/>
<TextBox BorderBrush="Black"/>
</DockPanel>
</Grid>
</Window>
上述程序下面2个栏中间不能进行左右拖动,无法改变显示尺寸。如果想实现左右拖动,使用Grid和GridSpliter(可以改变Grid初始设置的行宽和列高)
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="windows1" Height="300" Width="400" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Grid.ColumnSpan="3" BorderBrush="Black"/> <!--默认在(0,0)左上角-->
<TextBox Grid.Row="1" BorderBrush="Black"/> <!--缺省的坐标默认为0-->
<TextBox Grid.Row="1" Grid.Column="2" BorderBrush="Black"/>
<GridSplitter Grid.Column="1" Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Center" Width="5"
Background="Gray" ShowsPreview="True"/>
</Grid>
</Window>
WrapPanel
WrapPanel内部采用流式布局,Orientation控制延伸方向。在流延伸方向上会尽可能排列控件,排不下的会另起一行或一列继续排列。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1_8_18.MainWindow"
Title="windows1" Height="300" Width="400" >
<WrapPanel>
<Button Width="50" Height="50" Content="1"/>
<Button Width="50" Height="50" Content="2"/>
<Button Width="50" Height="50" Content="3"/>
<Button Width="50" Height="50" Content="4"/>
<Button Width="50" Height="50" Content="5"/>
<Button Width="50" Height="50" Content="6"/>
<Button Width="50" Height="50" Content="7"/>
<Button Width="50" Height="50" Content="8"/>
<Button Width="50" Height="50" Content="9"/>
<Button Width="50" Height="50" Content="10"/>
<Button Width="50" Height="50" Content="11"/>
</WrapPanel>
</Window>
显示效果如下:
当更改窗体尺寸大小时: