WPF 基础
XAML
XAML是基于XML的,它是WPF外在的表现形式。
XAML是一个纯粹的标记语言,这也就意味着某个元素要实现一个事件的处理时,需要在该元素中通过特定的属性来指定相应的事件处理方法名,
而真正的事件处理逻辑你可以通过C#或者VB.NET语言进行实现(代码后置方式),我们是没有办法通过XAML来编写相应的事件处理逻辑的。
在XAML中,每个属性都是和某个WPF类的属性相对应的,而且所有的元素名称都和WPF中定义的类名称相匹配。
在XAML文件中,可使用<x:code>元素,并将所有代码通过内联方式都封装在<![CDATA[...]]>标签中,以确保分析器不会对其中的代码进行解析。
<Button Name="button1" Click="Clicked">Click Me!</Button> <x:Code>
<![CDATA[ void Clicked(object sender, RoutedEventArgs e) { button1.Content = "Hello World"; } ]]>
</x:Code>
命名空间
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
默认引用WPF必须的dll: PesentationCore/PresentationFramework/System.Xaml/WindowBase
所有该命名空间下的对象元素都不需要使用前缀,如 <window/><Grid/><Button/>
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
如:x:Class/x:Key/x:Name/x:Static/x:Type/x:Code ...
其中 x:Key 最为常用,在同一个资源块中,所有 x:Key不能重名,因为它们同属于ResourceDirtionary
x:Class="WpfApplication1.MainWindow"
标记部份由 XAML 编译后,作为后台代码类 MainWindow.xaml.cs 的一部份,是 partial 的关系
xmlns:sys="clr-namespace:System;assembly=mscorlib"
引用系统DLL命名空间,如: 作为全局变量
<Window.Resources>
<sys:String x:Key="name">Apple</sys:String>
</Window.Resources>
<Button Content="{StaticResource ResourceKey=name}"></Button> === <Button Content="Apple"></Button>
xmlns:viewmodel="clr-namespace:MyWPF.ViewModels"
引用用户DLL命名空间
依赖属性
WPF界面控件中的属性,都可以称作是依赖属性,通过依赖属性,我们能够实现viewModel与界面元素属性之间进行绑定。
依赖属性所属类必须继承或间接继承自:System.Windows.DependencyObject类
触发器(属性、多条件、数据和事件触发器)
属性触发器: Trgger的 Property 来自所检查元素(TargetType所指)的依赖属性, 当其Value 为指定的值时, 驱动Setter变化
<Button MinWidth="75" Margin="10" Content="Submit"> <Button.Style> <Style TargetType="{x:Type Button}"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="Blue" /> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> <TextBox TextWrapping="Wrap" Margin="5" Width="100"> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Text" Value="Red"/> <Condition Property="IsMouseOver" Value="True"/> </MultiTrigger.Conditions> <Setter Property="Background" Value="Red"/> </MultiTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox> <TextBox MinWidth="50" TextWrapping="Wrap" Margin="5"> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="type me"> <Setter Property="Background" Value="Aqua"/> </DataTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox> <Window.Resources> <Style TargetType="Button"> <Style.Triggers> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.1" Duration="0:0:3"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Content="Submit"></Button> </Grid>
数据触发器: DataTrgger的 Property 来自DataContext所定义的非依赖属性, 当其Value 为指定的值时, 驱动Setter变化
<Style TargetType="dxg:GridControl"> <Style.Triggers> <DataTrigger Binding="{Binding CurrentView}" Value="AView"> <Setter Property="View" Value="BView"/> </DataTrigger> </Style.Triggers> </Style> ... <Button Content="{Binding CurrentView}" Grid.Row="0" Command="{Binding ChangeCurrentView}"/> <dxg:GridControl Grid.Row="1" DataSource="{Binding XXX}" AutoPopulateColumns="True" > </dxg:GridControl>
资源
xxx.Resources: 应用/窗体/控件级别的
ResourceDictionary: 文件级别的
引用资源方式:StaticResource/DynamicResource, 主要区别:一个是非运行时获取/一个是运行时获取(主要考虑需要在运行时更改资源值时,才使用)
资源是从下向上查找,如:
<StackPanel>
<StackPanel.Resources>
<sys:Double x:Key="msize"> <!--同名,由于不属于同一资源块-->
12
</sys:Double>
</StackPanel.Resources>
<Button FontSize="{DynamicResource ResourceKey= msize}">
<Button.Resources>
<sys:Double x:Key="msize"> <!--同名,由于不属于同一资源块-->
20
</sys:Double>
</Button.Resources>
font size is 20
</Button>
<Button FontSize="{DynamicResource ResourceKey= msize}">font size is 12</Button>
</StackPanel>
大括号转义写法:
<TextBlock Text="{}{Hello World!}" />
Binding
是源数据(属性/控件/集合/XML等等)在目标对象(UI Element)展现出的桥梁
与属性的绑定
<TextBox Text="{Binding Name}" />
与对象元素的绑定,如
<TextBox x:Name="txtName" />
<Label Content="{Binding ElementName=txtName, Path=Text}" />
与数据上下文对象绑定
class Person{
public string Name{get;set;}
public int Age{get;set;}
}
this.DataContext=new Person{Name="Apple", Age=20};
<TextBox Text="{Binding Path=Name}"></TextBox>
<TextBox Text="{Binding Path=Age}"></TextBox>
<TreeView ItemsSource="{Binding Source={StaticResource dataset}}">
......
主要用于同名无法确定的时候,可进行相对查找源:在 AncestorLevel和AncestorType 两参数进行设置
<TextBox Text="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type UIElement}}, Path=Name}">
</TextBox>
Binding.Mode
OneWay 源更新时,目标也更新
TwoWay 源更新时目标也更新,或者目标更新时同时更新源 (属性只读时,不可使用)
OneTime 目标只从源获取一次数据,之后互不影响
OneWayToSource 目标更新时, 源也更新
- 对源数据更新了,要自动影响目标对象展现, 则源灵气必须实现 INotifyPropertyChanged 接口.
- 与集合的绑定, 则需要这样: ObservableCollection<T> xxx
命令
命令: 通过实现 ICommand, 包括: Execute/CanExecute/CanExecuteChanged
命令源: 调用命令的对象, 通过实现 ICommandSource, 包括: Command/CommandTarget/CommandParameter
命令目标: 命令所作用的对象, 在 CommandTarget 中体现
命令绑定: 命令与事件之间的桥梁
布局
Grid: 行列方式,通过设置 RowDefinition,ColumnDefinition
Canvas: 坐标方式, 通过设置 ZIndex, Top, Left, Bottom, Right
StackPanel:层叠方式 ,通过设置 Orientation
DockPanel:泊位方式, 结合 StackPanel,通过设置父项 DockPanel 的 Dock
WarpPanel:可换行的 StackPanel,通过设置 ItemHeight,ItemWidth
模板
DataTemplete
用于显示 Content 的数据模板, 强调所绑定的Content以什么形式显示出来, 不影响其控件本身的外观.
通常这样来呈现:
首先在资源中定义DataTemplete, 如:
<DataTemplate DataType="{x:Type vm:XXXXXXViewModel}"> <v:XXXXXXView /> </DataTemplate>
然后在定义一个 ContentControl, 如:
<ContentControl Content="{Binding Path=XXXXXXViewModel}" />
这样XXXXXXViewModel将会在 <v:XXXXXXView/> 中呈现出来, 相当于把XXXXXXViewModel Binding 在 <v:XXXXXXView />中的DataContext
或者这样定义:
<ContentControl Content="{Binding Path=XXXXXXViewModel}"> <ContentControl.Resources> <DataTemplate DataType="{x:Type vm:XXXXXXViewModel}"> <v:XXXXXXView /> </DataTemplate> </ContentControl.Resources> </ContentControl>
<DataTemplate x:Key="MyTemplate" DataType="{x:Type vm:XXXXXXViewModel}"> <v:XXXXXXView /> </DataTemplate> <ListBox ItemTemplate="{StaticResource MyTemplate}" /> 或其他具有 ItemTemplate 的元素
ControlTemplate
用于设置控件具体的样式, 定义控件外观的模板, 跟内空没关系.
ItemsPanelTemplate
application相关触发的主要事件有
1. startup - 应用程序启动
2. exit - 应用程序关闭。
3. activated - 应用程序获得焦点时触发,也就是成为前台程序。
4. deactivated - 应用程序失去焦点时,也就是不再是前台程序时。
5. dispatcherunhandledexception - 当一个异常被抛出时,你可以选择处理或者是抛出该异常。
6. sessionending - windows正在关闭时,无论是注销还是关机,都会触发该事件。你可以选择取消关机。
你可以通过重写on[eventname]方法来添加对事件的处理, 如 onstartup。
window startup时会触发的事件有
- initialized - main window is being created
- isvisiblechanged - isvisible property set to true
- sizechanged - size property set to size of window
- layoutupdated - window layout changes
- sourceinitialized - window is attached to win32 window handle
- activated - window becomes foreground window
- previewgotkeyboardfocus - window getting focus
- iskeyboardfocuswithinchanged - iskeyboardfocuswithin property set to true
- iskeyboardfocusedchanged - iskeyboardfocused property set to true
- gotkeyboardfocus - window now has keyboard focus
- layoutupdated - window layout changes
- loaded - window is now laid out, fully rendered
- contentrendered - all window content has been rendered
window shutdown时触发的事件有:
- closing - window is going to close
- isvisiblechanged - isvisible property set to false
- deactivated - window becomes background window
- iskeyboardfocuswithinchanged - iskeyboardfocuswithin property set to false
- iskeyboardfocusedchanged - iskeyboardfocused property set to false
- lostkeyboardfocus - window no longer has keyboard focus
- closed - window is closing