wpf学习

XAML

对象元素

<></>
对象元素通常声明类型的实例

Application

创建

Application app=new Application(); app.run();

关闭

    关闭模式 ShutdownMode
  • OnLastWindowClose 默认
  • OnMainWindowClose
  • OnExplicitShutdown 仅在调用Application.Shutdown()时结束

生命周期

  1. Application.run()
  2. Startup
  3. 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 触笔类

焦点

键盘焦点:IsKeyboardFocused="true"
KeyBoard.FocusedElement(),具有键盘焦点的元素
Keyboard.Focus(element),将键盘焦点给予element

(逻辑焦点)焦点范围:FocusManager.IsFocusScope="true"
FocusManager.FocusedElement
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;
终止路由e.Handled=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>
  1. 应用程序级资源 App.xaml Application.Resources
  2. 窗体级资源 Window.xaml Window.Resources
  3. 文件级资源 MyResourceDictionary.xaml ResourceDictionary
  4. 对象(控件)级资源 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来处理挂起的输入事件

  1. 创建委托
    public delegate void NextPrimeDelegate();
  2. 调用 BeginInvoke(DispatcherPriority, Delegate)
    element.Dispatcher.BeginInvoke(DispatcherPriority.Normal,new NextPrimeDelegate(CheckNextNumber));

单独线程

  1. 创建委托
    private delegate void NoArgDelegate();
  2. 创建新线程
    NoArgDelegate fetcher = new NoArgDelegate(this.FetchWeatherFromServer);
    fetcher.BeginInvoke(null, null);
  3. 更新UI
    private void FetchWeatherFromServer() { ... element.Dispatcher.BeginInvoke(DispatcherPriority.Normal,new NoArgDelegate(UpdateUserInterface));}

全球化

多语言用户界面