XAML
对象元素
<></>
对象元素通常声明类型的实例
Application
创建
Application app=new Application(); app.run();
关闭
- 关闭模式 ShutdownMode
- OnLastWindowClose 默认
- OnMainWindowClose
- OnExplicitShutdown 仅在调用Application.Shutdown()时结束
生命周期
- Application.run()
- Startup
- Exit
布局
测量和排列子控件
Panel
Canvas:
使用相对于Canvas区域的坐标显式定位子元素
DockPanel:
子元素互相水平或垂直排列
Grid:
由行和列组成的网格
StackPanel:
将子元素排列成一行(可沿水平或垂直方向)
VirtualizingStackPanel:
将内容排列成一行(可沿水平或垂直方向),并使内容虚拟化
WrapPanel:
从左至右按顺序位置定位子元素,在包含框的边缘处将内容断开至下一行。 后续排序按照从上至下或从右至左的顺序进行,具体取决于Orientation属性的值。
绘图
形状
- Shape
- Line
- 可以在坐标(X1,Y1)到(X2,Y2)之间绘制一条线
- Rectangle
- 通过指定Width 和Height 可以绘制一个矩形
- Ellipse
- 椭圆
- Path
- 使用Path 类可以绘制一系列直线和曲线。Data 属性是Geometry 类型。还可以使用派生自基类Geometry的类绘制图形,或使用路径标记语法来定义图形
- Polygon
- 绘制由线段连接而成的封闭图形。多边形由一系列赋予Points 属性的Point 对象定义
- Polyline
- 绘制连接起来的线段
变换
画笔
- SolidColorBrush 纯色
- LinearGradientBrush 平滑的颜色变化
- RadialGradientBrush 以放射方式产生平滑的颜色渐变
- DrawingBrush 可以定义用画笔绘制的图形
- ImageBrush 把图像加载到画笔中
- VisualBrush 在画笔中使用其他WPF元素
属性
依赖项属性
基于其他输入的值计算属性值附加属性
数据绑定
SetBinding
数据源public class MyData : INotifyPropertyChanged
{
//......
public event PropertyChangedEventHandler PropertyChanged;
private string myDataProperty;
public String MyDataProperty
{
get { return myDataProperty; }
set
{
myDataProperty = value;
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs("MyDataProperty"));
}
}
}
}
绑定
MyData myDataObject = new MyData();
Binding myBinding = new Binding("MyDataProperty");
myBinding.Source = myDataObject;
myText.SetBinding(TextBlock.TextProperty, myBinding);
清除绑定
BindingOperations.ClearBinding(myText, TextBlock.TextProperty);
事件
路由事件
附加事件
输入
Keyboard 键盘类
Mouse 鼠标类
Stylus 触笔类
焦点
Keyboard.Focus(element),将键盘焦点给予element
FocusManager.SetIsFocusScope(element,true)
命令
- 命令模型:
- 命令是要执行的操作
- 命令源是调用命令的对象
- 命令目标是在其上执行命令的对象
- 命令绑定是将命令逻辑映射到命令的对象
命令 实现ICommand接口 : RoutedCommand
- Execute()在命令目标上引发PreviewExecuted和Executed事件
- CanExecute()在命令目标上引发CanExecute和PreviewCanExecute事件
- CanExecuteChanged
命令源 实现ICommandSource接口 : 控件,InputGesture
- Command调用命令源时执行的命令
- CommandTarget执行命令的对象(ICommand是RoutedCommand时才适用)
CommandTarget="{Binding ElementName=elementName}"
如果未定义命令目标,则具有键盘焦点的元素将用作命令目标 - CommandParameter用户定义的数据类型
命令目标
CommandBinding
- Command与之关联的命令
- PreviewExecuted,Executed实现命令逻辑
- PreviewCanExecute,CanExecute确定命令是否可以在当前命令目标上执行。e.CanExecute = true;
使用命令库
<CommandBinding Command="ApplicationCommands.New" Executed="NewCommandHandler" CanExecute="NewCanExecuteHandler" />
<Button Command="ApplicationCommands.New"/>
使用自定义RoutedCommand
public static RoutedCommand ExitRoutedCommand = new RoutedCommand();
<CommandBinding Command="{x:Static local:MainWindow.ExitRoutedCommand}" Executed="ExitCommandHandler" CanExecute="ExitCanExecuteHandler" />
<Button Command="ApplicationCommands.New"/>
资源 预定义对象
定义
<Xxx.Resources>
<ClassName x:Key="myKey" attribute=value />
</Xxx.Resoures>
- 应用程序级资源 App.xaml Application.Resources
- 窗体级资源 Window.xaml Window.Resources
- 文件级资源 MyResourceDictionary.xaml ResourceDictionary
- 对象(控件)级资源 ContentControl.Resources
使用
静态资源引用从控件所在的容器开始依次向上查找
"{StaticResource myKey}"
动态资源引用是从控件开始向上查找
"{DynamicResource myKey}"
加载资源词典
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceLib;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
样式
<Style BaseOn="{StaticRsource {x:Type Xxx}}"
TargetType="Xxx"
x:Key="styleName">
<Setter Property="property" Value="val"/>
<Setter Property="property">
<Setter.Value>
...
</Setter.Value>
<Setter/>
</Style>
模板
数据模板:数据(类,对象)的表现形式
<DataTemplate DataType="{x:type Xxx}"
x:Key="temName">
<Element attribute="{Binding Xxx.Property}"
</DataTemplate>
ControlTemplate控件模板:设置控件的外观
可视结构
<ControlTemplate TargetType="Xxx" x:Key="XxxName">
<RootElement>
<ContentPresenter />
</RootElement>
保留控件属性
attributeAlias="{TemplateBinding attribute}"
可视行为:控件处于特定状态时的控件外观
<VisualState x:Name="ControlState">
<Storyboard>
<ColorAnimation
Storyboard.TargeetName="AttrName"
Storyboard.TargetProperty="Color"
To="Transparent"
/>
</Storyboard>
</VisualState>
触发器
属性触发器
<Style.Triggers>
<Trigger Property="triggerPro" Value="true">
<Setter Property="controlPro" Value="val"/>
</Trigger>
...
</Style.Triggers>
事件触发器
<EventTrigger RoutedEvent="Mouse.MouseEnter">
线程处理模型
WPF 应用程序从两个线程开始:一个用于处理呈现,一个用于管理 UI。呈现线程有效地隐藏在后台运行,而 UI 线程则接收输入、处理事件、绘制屏幕以及运行应用程序代码。
UI 线程对一个名为 Dispatcher 的对象内的工作项进行排队。 Dispatcher 基于优先级选择工作项,并运行每一个工作项,直到完成。每个 UI 线程都必须至少有一个 Dispatcher,并且每个 Dispatcher 都只能在一个线程中执行工作项。
Windows 只允许创建 UI 元素的线程访问这些元素。后台线程通过向 UI 线程的 Dispatcher 注册工作项来请求 UI 线程代表它执行操作。
Dispatcher 类提供两个注册工作项的方法: Invoke 和 BeginInvoke。这两个方法均调度一个委托来执行。 Invoke 是同步调用,也就是说,直到 UI 线程实际执行完该委托它才返回。 BeginInvoke 是异步的,将立即返回。
辅助线程:利用UI线程空闲时间进行耗时计算
WPF线程模型不允许输入中断 UI 线程中正在进行的操作,必须定期返回到Dispatcher来处理挂起的输入事件
- 创建委托
public delegate void NextPrimeDelegate(); - 调用 BeginInvoke(DispatcherPriority, Delegate)
element.Dispatcher.BeginInvoke(DispatcherPriority.Normal,new NextPrimeDelegate(CheckNextNumber));
单独线程
- 创建委托
private delegate void NoArgDelegate(); - 创建新线程
NoArgDelegate fetcher = new NoArgDelegate(this.FetchWeatherFromServer);
fetcher.BeginInvoke(null, null); - 更新UI
private void FetchWeatherFromServer() { ... element.Dispatcher.BeginInvoke(DispatcherPriority.Normal,new NoArgDelegate(UpdateUserInterface));}