首先感谢刘铁锰先生的《深入浅出WPF》,学习WPF过程碰上很多新概念,如Data Binding、路由事件,命令、各种模板等。
WPF:编写CS端的UI技术。
怎么去掉WPF窗体靠上多出黑色的长条?在vs界面的菜单栏点击调试-选项,把启用XAML的UI调试工具勾选去掉即可。(我自己觉得偶尔会用用这个)
1 认识WPF
1.1 新建WPF项目
生成
Properties:资源 引用:引用其他类库 App.xmal:程序主体(一个GUI进程需要有一个窗体,App.xmal文件的作用声明了程序的进程,同时指定程序的主窗体),点开app.xaml.cs,它是app.xaml的后台代码。MainWindow1.xmal分支:默认程序的主窗体。
1.2 最简单的XAML代码
<Window x:Class="WPFTest1.MainWindow"
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"
xmlns:local="clr-namespace:WPFTest1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
x:Class是当XAML解析器将包含它的标签的解析成C#类的类名。是来自xmlns:x的命名空间。第一行xmlns是默认命名空间。<Window>和<Grid>都来自默认空间。Title是窗体标题,Height是窗体高度,Width是窗体宽度。可以引用CLS的命名空间。
引用第三方的类库:
xmlns:common(映射名,自定义)="clr-namespace:Common(类库中名称空间的名字);assembly=MyLibrary(类库名,比如MyLibrary.dll)"
- xmlns用于在Xaml中声明名称空间的Attribute
- 冒号的映射名是可选的
- 引号的字符串确定了哪个类库以及类库哪个名称空间
1.3 XAML文档的树形结构
<Window x:Class="WPFTest1.MainWindow"
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"
xmlns:local="clr-namespace:WPFTest1"
mc:Ignorable="d"
Title="MainWindow" Height="173" Width="296">
<StackPanel Background="LightBlue">
<TextBox x:Name='textBox1' Margin="5"></TextBox>
<TextBox x:Name='textBox2' Margin="5"></TextBox>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="textBox3" Width="140" Margin="5"/>
<TextBox x:Name="textBox4" Width="120" Margin="5"/>
</StackPanel>
<Button x:Name="button1" Margin="5">
<Image Source="C:\Users\14751\Pictures\Camera Roll\1.png" Width="23" Height="23"/>
</Button>
</StackPanel>
</Window>
树形框架结构如下:
<Window >
<StackPanel >
<TextBox ></TextBox>
<TextBox></TextBox>
<StackPanel ">
<TextBox />
<TextBox />
</StackPanel>
<Button>
<Image />
</Button>
</StackPanel>
</Window>
StackPanel可以把内部元素在纵向或横向上紧凑排列、形成栈式布局。也可以用Grid完成上面窗体,代码如下。
<Window x:Class="WPFTest1.MainWindow"
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"
xmlns:local="clr-namespace:WPFTest1"
mc:Ignorable="d"
Title="MainWindow" Height="173" Width="296">
<Grid Background="LightSlateGray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="33"/>
<RowDefinition Height="33"/>
<RowDefinition Height="33"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<TextBox x:Name="textBox1" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="5"/>
<TextBox x:Name="textBox2" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Margin="5"/>
<TextBox x:Name="textBox3" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="1" Margin="5"/>
<TextBox x:Name="textBox4" Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="1" Margin="5"/>
<Button x:Name="button5" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Margin="5">
<Image Source="C:\Users\14751\Pictures\Camera Roll\1.png" Width="23" Height="23"/>
</Button>
</Grid>
</Window>
WPF的布局原理:以<Window>对象为根节点,一层层向下包含。
1.4 使用Attribute为对象属性赋值
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Rectangle x:Name="rectangle" Width="200" Height="120" Fill="Blue"/>
</Grid>
Rectangle类对象Fill属性的类型是Brush,Brush是个抽象类的单色画刷,实际上编译成:
SoildColorBrush sBrush=new SoildColorBrush();
sBrush.Color=Color.Blue;
this.rectangle.Fill=sBrush;
......
使用TypeConveter类将XAML标签的Attribute与对象的Property进行映射。
1.5 径向渐变画刷
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Ellipse Width="120" Height="120">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.25,0.25" RadiusX="0.75" RadiusY="0.75">
<RadialGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Black" Offset="0.65"/>
<GradientStop Color="Gray" Offset="0.8"/>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
由此得出简化XAML的技巧:
- Attribute=value优于属性元素
- 充分利用默认值 StartPoint="0,0" EndPoint="1.1"是默认值,可省略
- 充分利用XAML简写方式,比如LinearGradientBrush.GradientStops的数据类型GradientStopCollection
1.6 标记扩展
标记扩展也是为属性赋值,只不过依赖于其他对象的属性值。尽管很方便,只有MarkupExtension类的派生类才能使用标记扩展语法。
<StackPanel Background="LightSlateGray">
<TextBlock Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}" Margin="5"/>
<Slider x:Name="slider1" Margin="5"/>
</StackPanel>
属性元素也可以做到,比较复杂:
<StackPanel Background="LightSlateGray">
<TextBox Margin="5">
<TextBox.Text>
<Binding ElementName="slider1" Path="Value" Mode="OneWay"></Binding>
</TextBox.Text>
</TextBox>
<Slider x:Name="slider1" Margin="5"/>
</StackPanel>
1.7 事件
当一个XAML标签对应着对象时,这个标签的一部分Attribute会对应这个对象的Property。
<Button Name="button1" Click="button1_Click"></Button>
在window. xaml.cs后面:
private void button1_Click(object sender, RoutedEventArgs e)
{
}
也可以直接在xaml写点击事件:
<Grid>
<Button Name="button1" Click="button1_Click"></Button>
</Grid>
<x:Code>
<![CDATA[
private void button1_Click(object sender, RoutedEventArgs e)
{
}
]]>
</:Code>
2 常用属性
2.1 x:classModifier
定义了XAML编译由标签编译生成的类具有的访问空指类别。internal与private等价。写internal可能编译报错,把window类的声明,把public改成internal。
2.2 x:Name
定义了控件名称,不能相同。
后台获取:
xaml代码:
<TextBox x:Name="textBox" Margin="5">
------
c#代码:
string txtName=textBox.Name;
2.3 x:FieldModifier
控件的访问级别。默认是internal。
2.4 x:Key
<Window.Resources>
<sys:String x:Key="myString">Hello WPF!</sys:String>
</Window.Resources>
<StackPanel>
<TextBox Text="{StaticResource ResourceKey=myString}" Margin="5"/>
</StackPanel>
使用String类,用xmlns:sys="clr-namespace:System;assembly=mscorlib"引用了mscorlib.dll,把System名称映射为sys名称空间。
string str=this.FindResource("myString") as string;
this.textBox1.Text=str;
2.5 x:Shared
把上面的x:Key当作资源放进资源字典后,需要设定检索的对象是同一个对象还是多个副本。
2.6 x命名空间中的标记扩展
2.6.1 x:Type
把某些对象资源放进资源字典里的数据类型。
mywindow.xaml
<StackPanel Background="LightBlue">
<TextBox Margin="5"></TextBox>
<TextBox Margin="5"></TextBox>
<TextBox Margin="5"></TextBox>
<Button Content="OK" Margin="5"/>
</StackPanel>
MyButton类
class MyButton:Button
{
public Type UserWindowType { get; set; }
protected override void OnClick()
{
base.OnClick();
Window win = Activator.CreateInstance(this.UserWindowType) as Window;
if (win != null)
{
win.ShowDialog();
}
}
}
MainWindow.xaml
<StackPanel>
<local:MyButton Content="Show" UserWindowType="{x:Type TypeName=local:mywindow}" Margin="5"/>
</StackPanel>
2.6.2 x:Null
显式地对一个属性赋一个空值。
<Buttob Content="OK" Style="{x:Null}">
下面一个例子,把一个Style放在window的资源里,并把它的x:Key和TargetType设置了Button类型,除了最后一个Button
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Width" Value="60"/>
</Style>
<StackPanel>
<Button Content="Ok"/>
<Button Content="Ok" Style="{x:Null}"/>
</StackPanel>
也可以写成
<Button Content="Ok" >
<Button.Style>
<x:Null/>
</Button.Style>
</Button>
2.6.3 x:Array
在WPF把包含的数据的对象称为数据源,如果把一个x:Array的实例作为数据源提供给一个ListBox。
<ListBox Margin="5">
<ListBox.ItemsSource>
<x:Array Type="sys:String">
<sys:String>Tim</sys:String>
<sys:String>Tom</sys:String>
<sys:String>Victor</sys:String>
</x:Array>
</ListBox.ItemsSource>
</ListBox>
2.6.3 x:Static
x:Static是一个很常用的标记扩展。功能是在XAML文档中使用数据类型的static成员。
pubic static string WindowTitle="山高月小";
public static string ShowText{get{return "水落石出";}}
<Window x:Class="Window1">
-----
Title="{x:Static local:Window1.WindowTitle}" Height="120" Width="300">
<StackPanel>
<TextBlock FontSize="32" Text="{x:Static local:Window1.ShowText}" />
</StackPanel>
</Window>
2.7 XAML指定元素
2.7.1 x:Code
可以让XAML包含一些本应放置在后置代码的C#代码。
2.7.2 x:XData
<Window.Resources>
<XmlDataProvider x:Key="InventoryData" XPath="Inventory/Books">
<x:XData>
<Supermarket xmlns="">
<Fruits>
<Fruit Name="Peach"/>
<Fruit Name="Banana"/>
<Fruit Name="Orange"/>
</Fruits>
<Drinks>
<Drink Name="Coca"/>
<Drink Name="PEPSI"/>
</Drinks>
</Supermarket>
</x:XData>
</XmlDataProvider>
</Window.Resources>
3 控件
我们把符合某类内容模型的UI元素称为一个族。以下是各种的内容模型。
3.1 ContentControl
单一内容控件。共同点:
- 派生自ContentControl
- 内容属性的名称为Content
- 只能由单一元素充当其内容
<StackPanel>
<Button Margin="5">
<TextBlock Text="Hello" />
</Button>
<Button Margin="5">
<Image Source=".\smile.png" Width="30" Height="30"/>
</Button>
</StackPanel>
想让Button的内容既包含文字又包含图片是不行的。
Button | ButtonBase | CheckBox | ComboBoxItem |
ContentControl | Frame | GridViewColumnHeader | GroupItem |
Lable | ListBoxItem | ListViewItem | NavigationWindow |
RadioButton | RepeatButton | ScrollViewer | StatusBarItem |
TpggleButton | ToolTip | U |