Wpf基础入门——控件Control篇

Posted Swbna

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wpf基础入门——控件Control篇相关的知识,希望对你有一定的参考价值。

本篇文章学习于: 刘铁猛老师《深入浅出WPF》

控件到底是什么?

WPF中是数据驱动UI , 数据是核心、是主动的;UI从属于数据并表达数据、是被动的。
Control是数据和行为的载体,而无需具有固定的形象。控件的派生关系如下:

WPF的内容模型

各类内容模型详解

我们把符合某类内容模型的UI元素称为一个族,每个族用它们共同基类来命名。

ContentControl 单一内容控件

本族元素的特点如下:

  • 均派生自 ContentControl 类。
  • 它们都是控件(Control)。
  • 内容属性的名称为Content。
  • 只能由单一元素充当其内容。【例如:Button控件属于这一族,但如果你想让Button的Content既包含文字又包含图片是不行的,但是我们可以先用一个可以包含多个元素的布局控件把图片和文字包装起来,再把这个布局控件作为Button的内容就好了】

HeaderedContentControl 带标题的单一内容控件

本族元素的特点如下:

  • 它们都派生自 HeaderedContentControl 类,HeaderedContentControl 是 ContentControl 类的

派生类。

  • 它们都是控件,用于显示带标题的数据。
  • 除了用于显示主体内容的区域外,控件还具有一个显示标题(Header)的区域。
  • 内容属性为Content和Header。
  • 无论是Content还是Header都只能容纳一个元素作为其内容。


下面这个例子是一个以图标为Header . 以文字为主体内容的GroupBox , 效果如下所示。

ItemsControl 以条目集合为内容的控件

本族元素的特点如下:

  • 均派生自ItemsControl类。
  • 它们都是控件,用于显示列表化的数据。
  • 内容属性为Items或ItemsSource。
  • 每种ItemsControl都对应有自己的条目容器(Item Container)


HeaderedItemsControl 带标题的以条目集合为内容的控件

顾名思义,本族控件除了具有ItemsControl的特性外,还具显示标题的能力。
本族元素的特点如下:

  • 均派生自 HeaderedItemsControl 类。
  • 它们都是控件,用于显示列表化的数据,同时可以显示一个标题。
  • 内容属性为 Items、ItemsSource 和 Header。

本族控件只有3 个:Menuitem 、 TreeViewitem、ToolBar。

Decorator 控件装饰元素

本族中的元素是在UI上起装饰效果的。如可以使用Border元素为一些组织在一起的内容加个边框。如果需要组织在一起的内容能够自由缩放,则可使用ViewBox元素。
本族元素的特点如下:

  • 均派生自Decorator类。
  • 起UI装饰作用。
  • 内容属性为 Child。
  • 只能由单一元素充当内容。

TextBlock和TextBox 显示文本

这两个控件最主要的功能是显示文本。TextBlock只能显示文本,不能编辑,所以又称静态文本。
TextBox则允许用户编辑其中的内容。
TextBlock虽然不能编辑内容,但可以使用丰富的印刷级的格式控制标记显示专业的排版效果。
TextBox不需要太多的格式显示,所以它的内容是简单的字符串,内容属性为Text。
TextBlock由于需要操纵格式,所以内容属性是Inlines (印刷中的“行”),同时,TextBlock也保留一个名为Text的属性,当简攀地显示一个字符串时,可以使用这个属性。

Shape 图形元素

友好的用户界面离不开各种图形的搭配,Shape族元素(它们只是简单的视觉元素,不是控件)就是专门用来在UI 上绘制图形的一类元素。这类元素没有自己的内容,我们可以使用Fill 属性为它们设置填充效果,还可以使用Stroke属性为它们设置边线的效果。
本族元素的特点如下:

  • 均派生自Shape类。
  • 用于2D图形绘制。
  • 无内容属性。
  • 使用Fill属性设置填充,使用Stroke属性设置边线。

Panel 面板类元素

之所以把Panel 族元素放在最后是因为这一族控件实在是太重要了一所有用于UI 布局的元素都属于这一族。
本族元素的特点如下:

  • 均派生自Panel抽象类。
  • 主要功能是控制UI布局。
  • 内容属性为Children。
  • 内容可以是多个元素,Panel元素将控制它们的布局。

UI布局(Layout)

布局元素属于Panel 族,这一族元素的内容属性是Children , 即可以接受多个控件作为自己的内容并对这些控件进行布局控制。WPF 的布局理念就是把一个布局元素作为ContentControl或HeaderedContentControl族控件的Content,再在布局元素里添加要被布局的子级控件,如果UI局部需要更复杂的布局,那就在这个区域放置一个子级的布局元素,形成布局元素的嵌套。
WPF中的布局元素有如下几个:

  • Grid:网格。可以自定义行和列并通过行列的数最、行髙和列宽来调整控件的布局。近似于HTML中的Table
  • StackPanel:栈式面板。可将包含的元素在竖直或水平方向上排成•条直线,当移除一个元素后,后面的元素会自动向前移动以填充空缺。
  • Canvas:画布。内部元素可以使用以像素为单位的绝对坐标进行定位,类似于WindowsForm编程的布局方式。
  • DockPanel:泊靠式面板。内部元素可以选择泊靠方向,类似于在Windows Form编程中设置控件的Dock属性。
  • WrapPanel:自动折行面板。内部元素在排满一行后能够自动折行,类似于HTML中的流式布局。

8天入门wpf—— 第四天 模板

    今天说下wpf中的模板,前面一篇中我们讲到了style,但是style所能做的仅仅是在现有控件的基础上进行修修补补,但是如果我们想
彻底颠覆控件样式,那么我们就必须使用这一篇所说的模板。

   老外写书都喜欢在篇头搞一个类图,方便我们宏观认识,这里我也上一个。

 

一:控件模板

1:ControlTemplate

   我们知道wpf的控件都是继承自Control,在Control类中有一个Template属性,类型就是ControlTemplate。

 

那么利用这个ControlTemplate就可以彻底的颠覆控件的默认外观,这里我把一个checkbox变成一个小矩形,蛮有意思的。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 Title="MainWindow" Height="350" Width="525">
6 <Window.Resources>
7 <ControlTemplate x:Key="rect" TargetType="x:Type CheckBox">
8 <StackPanel>
9 <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
10 <Rectangle.Fill>
11 <SolidColorBrush Color="White"/>
12 </Rectangle.Fill>
13 </Rectangle>
14 </StackPanel>
15 </ControlTemplate>
16 </Window.Resources>
17 <Canvas>
18 <CheckBox Template="StaticResource ResourceKey=rect" Content="我是CheckBox"/>
19 </Canvas>
20 </Window>


确实,我们干了一件漂亮的事情,把checkbox变成了“小矩形”,但是我们发现了一个小问题,为什么我的Content=“xxx”没有显示到模板上?

很简单,我们已经重定义了控件模板,默认模板将会被覆盖...

 

2:ContentPresenter

     幸好,wpf给我们提供了一个ContentPresenter,它的作用就是把原有模板的属性原封不动的投放到自定义模板中。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 Title="MainWindow" Height="350" Width="525">
6 <Window.Resources>
7 <ControlTemplate x:Key="rect" TargetType="x:Type CheckBox">
8 <StackPanel>
9 <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
10 <Rectangle.Fill>
11 <SolidColorBrush Color="White"/>
12 </Rectangle.Fill>
13 </Rectangle>
14 <ContentPresenter/>
15 </StackPanel>
16 </ControlTemplate>
17 </Window.Resources>
18 <Canvas>
19 <CheckBox Template="StaticResource ResourceKey=rect" Content="我是CheckBox"/>
20 </Canvas>
21 </Window>


当然你也可以玩一些小技巧,比如我想在"矩形“和”文字”中间设置边距,那么我们可以设置ContentPresenter的margin。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 Title="MainWindow" Height="350" Width="525">
6 <Window.Resources>
7 <ControlTemplate x:Key="rect" TargetType="x:Type CheckBox">
8 <StackPanel>
9 <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
10 <Rectangle.Fill>
11 <SolidColorBrush Color="White"/>
12 </Rectangle.Fill>
13 </Rectangle>
14 <ContentPresenter Margin="10" />
15 </StackPanel>
16 </ControlTemplate>
17 </Window.Resources>
18 <Canvas>
19 <CheckBox Template="StaticResource ResourceKey=rect" Content="我是CheckBox"/>
20 </Canvas>
21 </Window>


 

如果你够聪明,你会发现我设置的margin是一个非常呆板的事情,意思就是说能不能根据具体控件灵活控制margin呢?答案肯定是没问题的,

因为我们记得一个控件可以绑定到另一个控件上,比如这里我将模板中的Margin绑定到原控件中的Padding上去。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 Title="MainWindow" Height="350" Width="525">
6 <Window.Resources>
7 <ControlTemplate x:Key="rect" TargetType="x:Type CheckBox">
8 <StackPanel>
9 <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
10 <Rectangle.Fill>
11 <SolidColorBrush Color="White"/>
12 </Rectangle.Fill>
13 </Rectangle>
14 <ContentPresenter Margin="TemplateBinding Padding" />
15 </StackPanel>
16 </ControlTemplate>
17 </Window.Resources>
18 <Canvas>
19 <CheckBox Template="StaticResource ResourceKey=rect" Content="我是CheckBox" Padding="10"/>
20 </Canvas>
21 </Window>


 

3:Trigger

     我们知道style里面也是有trigger的,废话不多说,上代码说话。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 Title="MainWindow" Height="350" Width="525">
6 <Window.Resources>
7 <ControlTemplate x:Key="rect" TargetType="x:Type CheckBox">
8 <ControlTemplate.Resources>
9 <SolidColorBrush x:Key="redBrush" Color="Red"/>
10 </ControlTemplate.Resources>
11 <StackPanel>
12 <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
13 <Rectangle.Fill>
14 <SolidColorBrush Color="White"/>
15 </Rectangle.Fill>
16 </Rectangle>
17 <ContentPresenter/>
18 </StackPanel>
19 <ControlTemplate.Triggers>
20 <Trigger Property="IsChecked" Value="True">
21 <Setter TargetName="breakRectangle" Property="Fill" Value="StaticResource ResourceKey=redBrush">
22 </Setter>
23 </Trigger>
24 </ControlTemplate.Triggers>
25 </ControlTemplate>
26 </Window.Resources>
27 <Canvas>
28 <CheckBox Template="StaticResource ResourceKey=rect" Content="我是CheckBox"/>
29 </Canvas>
30 </Window>


 

最后形成的效果就是当checkbox选中时为实心框,不选中为空心框。

 

4:与Style混搭

   可能刚才我也说了,style只能在原有的控件基础上修修补补,如果我们让Style修补Control控件的Template属性时,此时我们是不是

就可以实现ControlTemplate和Style的混搭呢?

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 Title="MainWindow" Height="350" Width="525">
6 <Window.Resources>
7 <Style x:Key="cbx" TargetType="x:Type CheckBox">
8 <Setter Property="Template">
9 <Setter.Value>
10 <ControlTemplate TargetType="x:Type CheckBox">
11 <ControlTemplate.Resources>
12 <SolidColorBrush x:Key="redBrush" Color="Red"/>
13 </ControlTemplate.Resources>
14 <StackPanel>
15 <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
16 <Rectangle.Fill>
17 <SolidColorBrush Color="White"/>
18 </Rectangle.Fill>
19 </Rectangle>
20 <ContentPresenter/>
21 </StackPanel>
22 <ControlTemplate.Triggers>
23 <Trigger Property="IsChecked" Value="True">
24 <Setter TargetName="breakRectangle" Property="Fill" Value="StaticResource ResourceKey=redBrush">
25 </Setter>
26 </Trigger>
27 </ControlTemplate.Triggers>
28 </ControlTemplate>
29 </Setter.Value>
30 </Setter>
31 </Style>
32
33 </Window.Resources>
34 <Canvas>
35 <CheckBox Style="StaticResource ResourceKey=cbx" Content="我是CheckBox"/>
36 </Canvas>
37 </Window>


 

二:数据模板

   现在我们已经知道“控件模板”是用于改变控件外观,那么“数据模板”顾名思义就是控制数据的显示方式,下面做个demo让person绑定到listbox上。

1 namespace WpfApplication1
2
3 /// <summary>
4 /// MainWindow.xaml 的交互逻辑
5 /// </summary>
6 public partial class MainWindow : Window
7
8 public static string name = "一线码农";
9
10 public MainWindow()
11
12 InitializeComponent();
13
14
15
16 public class PersonList : ObservableCollection<Person>
17
18 public PersonList()
19
20 this.Add(new Person() Name = "一线码农", Age = 24, Address = "上海" );
21 this.Add(new Person() Name = "小师妹", Age = 20, Address = "上海" );
22
23
24
25 public class Person
26
27 public string Name get; set;
28
29 public int Age get; set;
30
31 public string Address get; set;
32
33
xaml:

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 xmlns:src="clr-namespace:WpfApplication1"
6 Title="MainWindow" Height="350" Width="525">
7 <Window.Resources>
8 <ObjectDataProvider x:Key="personList" ObjectType="x:Type src:PersonList"/>
9 </Window.Resources>
10 <Grid>
11 <ListBox ItemsSource="Binding Source=StaticResource ResourceKey=personList"></ListBox>
12 </Grid>
13 </Window>


最后我们发现,listbox中并没有呈现我们需要的数据,只是呈现了当前类的ToString()方法,很简单,因为我们绑定的不是简单的数据类型集合,

而是多字段的复杂类型,更重要的是我们并没有告诉wpf该如何呈现person数据。

<1>重写Tostring()

    既然wpf在Render数据的时候呈现的是当前的ToString()形式,那下面我们来重写ToString()试试看。

1 public class Person
2
3 public string Name get; set;
4
5 public int Age get; set;
6
7 public string Address get; set;
8
9 public override string ToString()
10
11 return string.Format("姓名:0, 年龄:1, 地址:2", Name, Age, Address);
12
13
最后看看效果,如我们所愿,person信息已经呈现。

 

<2>DataTemplate重写

   或许有的人比较苛刻,他需要person是作为矩形一块一块的呈现,而不是这些简单的形式,那么此时我们就可以用DataTemplate来颠覆。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 xmlns:src="clr-namespace:WpfApplication1"
6 Title="MainWindow" Height="350" Width="525">
7 <Window.Resources>
8 <ObjectDataProvider x:Key="personList" ObjectType="x:Type src:PersonList"/>
9 <DataTemplate x:Key="rect">
10 <Border Name="border" BorderBrush="Aqua" BorderThickness="1" Padding="5" Margin="5">
11 <StackPanel>
12 <StackPanel Orientation="Horizontal">
13 <TextBlock Text="Binding Name" Margin="5,0,0,0"/>
14 <TextBlock Text="Binding Age" Margin="5,0,0,0"/>
15 </StackPanel>
16 <StackPanel Orientation="Horizontal">
17 <TextBlock Text="Binding Address" Margin="5,0,0,0"/>
18 </StackPanel>
19 </StackPanel>
20 </Border>
21 </DataTemplate>
22 </Window.Resources>
23 <Grid>
24 <ListBox ItemsSource="Binding Source=StaticResource ResourceKey=personList"
25 ItemTemplate="StaticResource ResourceKey=rect"></ListBox>
26 </Grid>
27 </Window>


哈哈,果然是以一块一块的形式展现,大功告成,当然这里的”触发器“和”style混搭“跟ConrolTemplate非常相似,我想应该不需要累赘了。

 

三: ItemsPanelTemplate

      在条目控件(ItemControl)里面,有一个属性叫ItemPanel,类型是ItemPanelTemplate。

 

那么ItemsPanelTemplate主要用来干什么的呢?首先我们要知道常见的条目控件有:ListBox,Menu,StatusBar,比如拿ListBox来说,

我们经过仔细研究,发现ItemBox的ItemPanel其实是一个VisualizingStackPanel,就是说ListBox的每一项的排列方式是遵循StackPanel的

原则,也就是从上到下的排列方式,比如”一线码农“和”小师妹“是按照竖行排列方式,好,我现在的要求就是能够”横排“,该如何做到呢?

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 xmlns:src="clr-namespace:WpfApplication1"
6 Title="MainWindow" Height="350" Width="525">
7 <Window.Resources>
8 <ObjectDataProvider x:Key="personList" ObjectType="x:Type src:PersonList"/>
9 <DataTemplate x:Key="rect">
10 <Border Name="border" BorderBrush="Aqua" BorderThickness="1" Padding="5" Margin="5">
11 <StackPanel>
12 <StackPanel Orientation="Horizontal">
13 <TextBlock Text="Binding Name" Margin="5,0,0,0"/>
14 <TextBlock Text="Binding Age" Margin="5,0,0,0"/>
15 </StackPanel>
16 <StackPanel Orientation="Horizontal">
17 <TextBlock Text="Binding Address" Margin="5,0,0,0"/>
18 </StackPanel>
19 </StackPanel>
20 </Border>
21 </DataTemplate>
22 <ItemsPanelTemplate x:Key="items">
23 <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"/>
24 </ItemsPanelTemplate>
25 </Window.Resources>
26 <Grid>
27 <ListBox ItemsSource="Binding Source=StaticResource ResourceKey=personList"
28 ItemTemplate="StaticResource ResourceKey=rect" ItemsPanel="StaticResource ResourceKey=items"></ListBox>
29 </Grid>
30 </Window>


哈哈,确实有意思,我们改变了ListBox中Item的默认排序方向,当然在menu,statusBar中我们也可以用同样的方式来更改。

 

四: HierarchicalDataTemplate

       它是针对具有分层数据结构的控件设计的,比如说TreeView,相当于可以每一个层级上做DataTemplate,很好很强大。

1 <Window x:Class="WpfApplication1.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 xmlns:src="clr-namespace:WpfApplication1"
6 Title="MainWindow" Height="350" Width="525">
7 <Window.Resources>
8 <XmlDataProvider x:Key="Info" XPath="Nations">
9 <x:XData>
10 <Nations xmlns="">
11 <Nation Name="中国">
12 <Provinces>
13 <Province Name="安徽">
14 <Citys>
15 <City Name="安庆">
16 <Countrys>
17 <Country Name="潜山"/>
18 <Country Name="桐城"/>
19 </Countrys>
20 </City>
21 <City Name="合肥">
22 <Countrys>
23 <Country Name="长丰"/>
24 <Country Name="肥东"/>
25 </Countrys>
26 </City>
27 </Citys>
28 </Province>
29 <Province Name="江苏">
30 <Citys>
31 <City Name="南京">
32 <Countys>
33 <Country Name="溧水"/>
34 <Country Name="高淳"/>
35 </Countys>
36 </City>
37 <City Name="苏州">
38 <Countys>
39 <Country Name="常熟"/>
40 </Countys>
41 </City>
42 </Citys>
43 </Province>
44 </Provinces>
45 </Nation>
46 </Nations>
47 </x:XData>
48 </XmlDataProvider>
49 <HierarchicalDataTemplate DataType="Nation" ItemsSource="Binding XPath=Provinces/Province">
50 <StackPanel Background="AliceBlue">
51 <TextBlock FontSize="20" Text="Binding [email protected]"/>
52 </StackPanel>
53 </HierarchicalDataTemplate>
54 <HierarchicalDataTemplate DataType="Province" ItemsSource="Binding XPath=Citys/City">
55 <StackPanel Background="LightBlue">
56 <TextBlock FontSize="18" Text="Binding [email protected]"/>
57 </StackPanel>
58 </HierarchicalDataTemplate>
59 <HierarchicalDataTemplate DataType="City" ItemsSource="Binding XPath=Countrys/Country">
60 <StackPanel Background="LightBlue">
61 <TextBlock FontSize="18" Text="Binding [email protected]"/>
62 </StackPanel>
63 </HierarchicalDataTemplate>
64 <HierarchicalDataTemplate DataType="Country">
65 <StackPanel Background="LightSalmon">
66 <TextBlock FontSize="18" Text="Binding [email protected]"/>
67 </StackPanel>
68 </HierarchicalDataTemplate>
69 </Window.Resources>
70 <TreeView ItemsSource="Binding Source=StaticResource ResourceKey=Info,XPath=Nation"></TreeView>
71 </Window>
---------------------
作者:一线码农
来源:CSDN
原文:https://blog.csdn.net/huangxinchen520/article/details/64921934
版权声明:本文为博主原创文章,转载请附上博文链接!

以上是关于Wpf基础入门——控件Control篇的主要内容,如果未能解决你的问题,请参考以下文章

8天入门wpf—— 第四天 模板

WPF自学入门WPF-XAML布局控件

[WPF自定义控件]从ContentControl开始入门自定义控件

WPF - 8.控件类

Zara带你快速入门WPF---触发器篇

WPF入门基础教程之布局