1. 前言
1. 数据驱动 UI
WPF 是数据核心、主动的,UI 从属数据并表达数据、是被动的;
不再是 UI 驱动数据,而是数据驱动 UI;
2. 控件的定义
控件、数据内容、行为(控件响应用户操作执行自己的方法或以事件的形式通知应用程序);
1)控件是数据和行为的载体;
2)所以关注控件时应该关注抽象的数据和行为而不是具体的形象,
3)比如符合"能展示内容并相应用户单击"这一抽象概念的 UI 元素都可以是 Button,而具体的样子完全可以通过 Style 和 Template 决定,checkbox 也不是因为有个 box 可以 check 才叫 checkbox。
3. 控件类型
- 布局控件:Grid、StackPanel、DockPanel、WarpPanel 等 Panel 的子类;
- 内容控件:只能容纳一个其他控件或布局控件作为它的内容。如 Window、Button 等 ContentControl 的子类;
- 带标题的内容控件:GroupBox、TabItem 等 HeaderedContentControl 的子类;
- 条目控件:显示一列数据,一般这列数据之间的类型一致;ListBox、ComboBox 等 ItemsControl 的子类;
- 带标题的条目控件:TreeViewItem、MenuItem 等 HeaderedContentControl 的子类;
<TreeView>
<TreeViewItem Header="A">
<TreeViewItem Header="A1">A11</TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="B">
<TreeViewItem Header="B1">B11</TreeViewItem>
</TreeViewItem>
</TreeView>
<Menu>
<MenuItem Header="菜单">
<MenuItem Header="新建" InputGestureText="Ctrl+N">
<MenuItem.Icon>
<Image Source="/Images/2.png"/>
</MenuItem.Icon>
<MenuItem Header="设备" Click="MenuItem_Click"/>
</MenuItem>
</MenuItem>
<MenuItem Header="设置" />
<MenuItem Header="关于" />
</Menu>
- 特殊内容控件:TextBox、TextBlock、Image
graph LR
DependencyObject-->Dispatcher
Visual-->DependencyObject
UIElement-->Visual
FrameworkElement-->UIElement
Panel-->FrameworkElement
Control-->FrameworkElement
TextBlock-->FrameworkElement
Image-->FrameworkElement
ContentControl-->Control
HeaderedContentControl-->ContentControl
ItemsControl-->Control
HeaderedItemsControl-->ItemsControl
TextBox-->Control
2. 内容模型
2.1 逻辑树、可视元素树
可视树:因为 WPF 有Content 的概念,使控件与控件之间可以存在包含关系,以窗体为根,整个 WPF 的 UI 才形成树形结构。
2.2 内容属性
不同控件的内容属性名称不一:Content、Child、Items、Children、Text;
Button.Content、StackPanel.Children、ListBox.Items。
2.3 各类内容模型详解
2.3.1 ContentControl 族
- 内容属性:Content
- 常用:
Button、Window、Label、UserControl、
ListBoxItem、ListViewItem、ComboBoxItem、
RadioButton、ToggleButton、CheckBox、
ToolTip、ScrollViewer、ContentControl; - 不常用:
ButtonBase、GroupItem、RepeatButton、StatusBarItem、NavigationWindow、Frame、GridViewColumnHeader
2.3.2 HeaderedContentControl
- 内容属性:Content、Header
- 常用:TabItem、Expander、HeaderedContentControl
- 不常用:GroupBox
2.3.3 ItemsControl
- 内容属性:Items 或 ItemsSource
每种 ItemsControl 都对应有自己的条目容器 Item Container,如 ListBox 的 Item Container 是 ListBoxItem,关键词:包装机制 - 常用:
ListBox、ListView、ComboBox、Menu、ContextMenu、ItemsControl、TabControl、TreeView、StatusBar - 不常用:
MenuBase、Selector(ListBox、ComboBox、TabControl 等的父类)
2.3.3.1 ListBox
- DisplayMemberPath、SelectedValue、SelectedValuePath、SelectedItem、SelectedItems
ItemsContorl | Item Container |
---|---|
ComboBox | ComboBoxItem |
ListBox | ListBoxItem |
ListView | ListViewItem |
TabControl | TabItem |
Menu | MenuItem |
ContextMenu | MenuItem |
TreeView | TreeViewItem |
StatusBar | StatusBarItem |
2.3.4 HeaderedItemsControl
内容属性:Items 或 ItemsSource、Header
常用:
MenuItem、TreeViewItem、ToolBar
2.3.5 Decorator 族
- 内容属性: Child
起 UI 装饰作用 - 常用:
Border、ViewBox - 不常用:
ButtonChrome、ListBoxChrome、BulletDecorator、InkPresenter、AdornerDecorator、ClassicBorderDecorator、SystemDropShadowChome
2.3.6 TextBox、TextBlock
2.3.7 Shape 族
- Path、Polygon、Polyline 等 Shape 子类;
- Stroke 设置边线、Fill 设置填充;
- 无内容属性;
- 用于 2D 图形绘制。
<Polygon Points="10,10 100,125 20,125" Stroke="Red"/>
<Polyline Points="10,10 100,125 20,125" Stroke="Red"/>
<Path Stroke="Red">
<Path.Data>
<PathGeometry Figures="M 10,100 C 10,300 300,-160 100,10"/>
</Path.Data>
</Path>
<Path Data="M 12.37,87.5 A 15,15 0 0 0 60,115" Stroke="Red" />
Path:
起点命令 M,终点命令 Z(让头尾相连)
直线 L,水平直线 H,垂直直线 V,曲线 C、Q、S、T
椭圆 A
2.3.8 Panel 族
- 内容属性:Children
- 常用:
Grid、StackPanel、DockPanel、WrapPanel、Canvas - 不常用:
UniformGrid(Grid 简化版,定义几行几列,每个单元格大小一致)、TabPanel、ToolBarOverflowPanel、ToolBarPanel、VirtualizingPanel、VirtualizingStackPanel
2.3.8.1 Grid
- Grid 共享尺寸属性 SharedSizeGroup 运用:
1)将父级 Grid 的 Grid.IsSharedSizeScope 设置为 true;
2)两个 Grid 各自某一行或某一列的 SharedSizeGroup 设置为同一个字符串,那么这两行或这两列就可以共享空间。
<Grid Grid.IsSharedSizeScope="True">
<Grid x:Name="layer0Grid"
Panel.ZIndex="0"
MouseEnter="layer0Grid_MouseEnter">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
...
</Grid>
<Grid x:Name="toolboxLayerGrid" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" SharedSizeGroup="ToolboxGroup" />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Width="3" HorizontalAlignment="Left" />
<Grid x:Name="toolboxGrid" Grid.Column="1" Margin="3,0,0,0">
</Grid>
</Grid>
</Grid>
toolboxLayerGrid.Visibility = System.Windows.Visibility.Visible;
toolboxLayerGrid.SetValue(Grid.ZIndexProperty, 2);
layer0Grid.ColumnDefinitions.Add(new ColumnDefinition { SharedSizeGroup = "ToolboxGroup" });
- Grid 宽高接受的尺寸单位:Pixel(像素,默认单位)、Inch(英寸=96 piexl)、Centimeter(厘米=96/2.54 pixel)、Point(=96/72 pixel)
- 如果把两个元素放在 Grid 的同一个单元格内,则后书写的元素将在先书写的元素之上,可以通过 Panel.ZIndex 值调整,值越大,越靠上。默认为 1.
2.3.8.2 StackPanel
- Orientation 决定横向排列还是纵向排列;
- 布局风格:垒积木
2.3.8.3 Canvas
- Canvas.Top 、Canvas.Left;
- 用于基本不改动、艺术性比较强、需要大量使用横坐标作为绝对定位、依赖横坐标的动画等场景;
- 两个元素占据同一个位置时,跟 Grid 一样。
2.3.8.4 DockPanel
- LastChildFill
2.3.8.5 WrapPanel
- 流式布局,Orientation 默认 Horizontal:从左到右 从上到下。