WPF pro 4.5 Top

WPF Classic

WPF Introduction

1.4 WPF体系结构

Core Class

System.Threading.DispatcherObject

单线程亲和模型

继承自DispatcherObject类,可以让界面元素检查代码是否在正确的线程上运行

System.Windows.DependencyObject

依赖属性

System.Windows.Media.Visual class

可将Visual类视为绘图对象

System.Windows.UIElement class

增加了对WPF本质特征的支持

System.Windows.FrameworkElement Clas

HorizontalAlignment

Margin

Animation

Style

etc.

System.Windows.Shapes.Shape Class

形状类 Rectangle Polygon Ellipse Line Path

System.Windows.Controls.Control Class

Control : TextBox Button ListBox

System.Windows.Controls.ContentControl

是所有具有单一内容的控件的基类

System.Windows.Controls.ItemsControl

所有显示选项集合的控件的基类 ListBox or TreeView

System.Windows.Controls.Panel

所有布局容器的基类

1.6 Conclusion

  • 硬件加速
  • 分辨率无关性
  • 控件无固定外观
  • 声明式用户界面
  • 基于对象的绘图

XAML

2.2 XAML basic

顶级元素

  • Window
  • Page
  • Application

Xaml生成的是partial类 与C#定义合为一个类

InitializeComponent() 是默认的构造函数,工作是调用LoadComponent()方法

等价?

2.3 Xaml中的属性和事件

XML的特性值总是纯文本字符串,但是对象可以是任何.net类型,因此需要用到类型转换器执行转换 TypeConverter

复杂属性

属性元素语法

标记扩展 {标记扩展类 参数} 语法

1
<Button ... Foreground="{x:Static SystemColors.ActiveCaptionBrush}">

==

1
2
3
4
5
<Button>
<Button.Foreground>
<x:Static Member="SystemColors.ActiveCaptionBrush"></x:Static>
</Button.Foreground>
</Button>

Attached Property

附加属性是可用于多个控件但在另一个类中定义的属性。在WPF中,附加属性常用于控件布局

Grid.SetRow(texQuestion,0)

包含句点的 LinearGradientBrush.GradientStops是复杂属性。如果复杂属性实现了IList或者IDictionary接口

解释器就使用IList.Add()方法添加对象

xaml 字符实体

coma write
< &lt ;
> &gt ;
& &amp ;
引号 &quot ;

WFP Layout

Panel

public properties

Background Children IsItemsHost

Classes

StackPanel

WrapPanel

DockPanel

Grid

UniformGrid

Canvas

TabPanel

ToobarPanel

VirtualizingStackPanel

InkCanvas

3.2Layout Property

3.2.1

HorizontalAlignment

VerticalAlignment

Margin

MinWidth MinHeight

MaxWidth MaxHeight

Width Height

Conclusion

4.Dependency Properties

You can use Reflector to do it;

Routed Events

The Coercion Callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.CoerceValueCallback = new CoerceValueCallback(CoerceMaximum);
DependencyProperty.Register("Maximum",typeof(double),typeof(RangeBase),metadata);

private static object CoerceMaximum(DependencyObject d,object value)
{
RangeBase base1= (RangeBase)d;
if(((double)value)<base1.Minimum)
{
return base1.Minimum;
}
return value;

}

internal static object ConstrainToRange(DependencyObject d,object value)
{
double newValue =(double)value;
RangeBase base1=(RangeBase)d;

double minimum=base1.Minimum;
if(newValue<minimum)
return minimum;

double maximum=base1.maximum;
if(newValue>maximum)
{
return maximum;
}
return newValue;
}



private static void OnMinimumChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
RangeBase base1 =(RangeBase)d;
...
base1.CoerceMaximum(RangeBase.MaximumProperty);
base1.CoerceValue(RangeBase.ValueProperty);
}

private static void OnMaximumChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
RangeBase base1=(RangeBase)d;
...
base1.CoerceValue(RangeBase.ValueProperty);
base1.OnMaximumChanged((double) e.OldValue,(double)e.NewValue);
}

5.2.1 RoutedEventArgs

Properties:

Source

OriginalSource

RoutedEvent

Handled

Attached Events

1
2
3
<StackPanel Button.Click="DoSomething" Margin="5">
<Button></Button>
</StackPanel>

The Click Event is actually defined in the ButtonBase Class…

代码中关联附加事件时 不能用+=

1
pnlButtons.AddHandler(Button.Click,new RoutedEventHandler(DoSomething));

WPF EVents

events catagories:

Lifetime events

Mouse events

Keyboard events

Stylus events

Multitouch events

Lifetime Events

Initialized

Loaded

Unloaded

For Window

SourceInitialized

ContentRendered

Activated

Deactivated

Closing

Closed

Input Events

Keyboard Input

Handling a Key Press

Focus

Getting Key State

Mouse Input

MouseEventArgs —–a little like Transform

Multitouch Input

The last world

Controls

The Control Class

Background and Foreground

Setting Colors in Code

1
2
3
4
5
6
cmd.Background = new SolidColorBrush(Colors.AliceBlue);
cmd.Background = new SolidColorBrush(SystemColors.ControlColor);
cmd.Background = SystemColors.ControlBrush;
int red=0;int green=255;int blue =0;
cmd.Foreground = new SolidColorBrush(Color.FromRgb(red,green,blue));
cmd.Foreground = new SolidColorBrush(Color.FromArgb(red,green,blue.0.5));

Fonts

1
<Button Name="cmd" FontFamily="Times New Roman" FontSize ="18">A Button</Button>

Same as

1
2
cmd.FontFamily ="Times New Roman";
cmd.FontSize="18";

<TextBlock TextDecorations="Underline">Underlined text</TextBlock>

Mouse Cursors

Fonts

文本格式化模式,字体低于15时,可以使用GDI风格的文本渲染,增加TextOptions.TextFormattingMode附加属性,并且设置为Display

TextOptions.TextFormattingMode="Display"

Mouse Cursors

<Button Cursor="Help">Help</Button>

重叠光标,内部也是可以的

ForceCursor属性,可以使父元素覆盖子元素的光标

如果希望为应用程序每个窗口中的每个元素应用光标设置,则使用

1
2
Mouse.OverrideCursor =Cursors.Wait;
Mouse.OverrideCursor = null;

自定义光标也是可以的

1
2
Cursor customCursor = new Cursor(Path.Combine(applicationDir,"stopwatch.ani"));
this.Cursor =customCursor;
1
2
3
4
StreamResourceInfo sri =Application.GetResourcesStream(
new Uri("stopwatch.ani",UriKind.Relative));
Cursor customCursor = new Cursor(sri.Stream);
this.CUrsor =customCursor;)

Content Controls

6.2.1 Content 属性

Control类有Content属性支持两大类

  • 未继承自UIElement类的对象 使用ToString()显示文本
  • 继承自UIElement类的对象 使用UIElement.OnRender()显示文本

Check Box

是可空类型,接口实现于ToggleButton类,IsChecked~~于是属性可以设置为 true/false null

<CHeckBox IsChecked="{x:Null}">A Check box in indeterminate state</CheckBox>

IsThreeState:决定用户是否能把复选框设置为不确定状态

RadioButton

通常用GroupBox封装 单选按钮

Tooltips

ToolTip属性在FrameworkElement类中定义,所有能放窗口的元素都可以使用该属性

<Button ToolTip="This is my tooltip">I have a tooltip</Button>

ToolTip不能接收焦点

Properties:

HasDropShadow

Placement

HorizontalOffset

VerticalOffset

PlacementTarget

PlacementRectangle

CustomPopupPlace

ToolTip放置策略有一堆

ToolTipService 附加属性

1
2
<Button ToolTipService.InitialShowDelay="1">
</Button>

Properties:

InitialShowDelay

ShowDuration

BetweenShowDelay

Tooltip

HasDropShadow

ShowOnDisabled

Placement/PlacementTarget/

PlacementRectangle/VerticallOffset

The Popup

与Tooltop区别更重要

  • Popup控件永远不会自动显示。要显示要用IsOpen
  • 默认情况下Popup.StaysOpen属性被设置为true,直到明确地设置IsOpen属性为false
  • Popup 提供PopupAnimation属性,如果IsOpen为true,可以控制Popup进入视野的方式。可以选择None Fade Scroll 以及Slide 为了使用动画,设置AllowsTransparency属性为true
  • 可以接收焦点
  • 定义在System.Windows.Controls.Primitive

6.3 Specialized Containers

6.3.1 ScrollViewer

VerticalScrollBarVisibility属性控制滚动条显示

自定义滚动

  1. 在ScrollViewer控件中放置能滚动的元素,即实现了IScrollInfo的元素
  2. 设置ScrollViewer.CanContentScroll
  3. 自定义滚动

实现了IScrollInfo 接口的元素很少,如StackPanel,如果设置CanContentScroll属性为true,则从元素滚到元素,否则像素滚

6.3.2 GroupBox

6.3.3 TabItem

6.3.4 Expander

折叠扩展,可以设置IsExpanded来改变是否折叠

与其他控件同步,可处理Expanded和Collapsed事件

内容太多需要拓展时。

  1. 为窗口设置最小尺寸
  2. 设置SizeToContent属性
  3. hard-coding height and width
  4. Create a scrollable expandable region by ScrollViewer
1
2
3
4
5
6
7
<Expander Margin="5" Padding="5" Header="Region Two">
<ScrollViewer Height="50">
<TextBlock TextWrapping="Wrap">
...
</TextBlock>
</ScrollViewer>
</Expander>

6.3.5 Text Controls

6.3.6 Multiple Lines of Text

use the handy MinLines and MaxLines properties

use IsReadOnly property or IsEnabled…Think

6.3.7 Text Selection

TextBox property SelectionStart SelectionLength SelectedText

AutoWordSelection.–直接全选

Undo() CanUndo

Spell Checking

<TextBox SpellCheck.IsEnabled="True">...</TextBox>

6.3.8 PasswordBox

Like TextBox has property MaxLength Method: Clear() Paste() SelectAll()

Event: PasswordChange

using System.Security.SecureString Object

SecureString.Dispose()

6.5 List Controls

event SelectionChanged

1
2
3
4
5
6
7
private void lst_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
if(lst.SelectedItem==null ) return;
txtSelection.Text=String.Format(
"You chose item at Position{0}.\r\nChecked state is {1}",
lst.SelectedIndex,((CheckBox)lst.SelectedItem).IsCHecked);
}

SelectedItem 读取

6.5.2 ComboBox

下拉框

6.6 Range_based Controls

Including ScrollBar/ ProgressBar / Slider inherited from RangeBase Class which is from Control class

RangeBase Properties

Value

Maximum

Minimum

SmallChange

LargeChange

通常不使用ScrollBar 更高级的ScrollViewer 更有用

Slider和Progressbar 更实用

6.6.1 Slider

Properties:

Orientation

Delay

Interval

TickPlacement

TickFrequency

Ticks

IsSnapToTickEnabled

IsSelectionRangeEnabled

6.6.2 ProgressBar

1
2
3
<StackPanel Margin="5">
<ProgressBar Height="10" IsIndeterminate="True"></ProgressBar>
</StackPanel>

6.7 Date Controls

Calendar and DatePicker

properties

DisplayDateStart

DisplayDateEnd

BlackoutDates

SelectedDate

SelectedDates

DisplayDate

FirstDayOfWeek

IsTodayHighlighted

DisplayMode

SelectionMode

IsDropDownOpen

SelectedDateFormat

Event

SelectedDateChanged (DatePicker) or SelectedDatesChanged in Calendar

Text Controls

List Controls

Range_Based COntrols

Date Controls

THe last world

Ch07 Application Class

7.1.3 Application Shutdown

ShutdownMode Enumeration

OnLastWindowClose

OnMainWindowClose

OnExplicitShutdown

7.2.1 显示初始界面

上传图片修改为splashScreen

7.2.2 处理命令行参数

命令行在 项目的 属性-调试里

7.2.3 访问当前Application对象

1
2
MainWindow main= (MainWindow)Application.Current.MainWindow;
main.DoSomething();

7.2.4 在窗口之间进行交互

1
2
3
4
5
6
7
8
9
10
public partial class App : Application
{
private List<Document> documents = new List<Document>();

public List<Document> Documents
{
get { return documents; }
set { documents = value; }
}
}

添加到App class中 作为引用,类似 GameManager

7.2.5 单实例应用程序

  1. 创建单实例应用程序封装器。添加Microsoft.VisualBasic.dll程序集的引用,自定义类继承自Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.
  2. IsSingleInstance
  3. OnStartup
  4. OnStartupNextInstance()

7.3 Assembly Resources

7.3.2 检索资源

1
2
StreamResourceInfo sri = Application.GetResourcesStream(
new Uri("images/winter.jpg",UriKind.Relative));
1
2
3
4
5
6
7
8
9
Assembly assembly = Assembly.GetAssembly(this.GetType());
string resourceName= assembly.GetName().Name+".g";
ResourceManager rm = new ResourceManager(resourceName,assembly);
using(ResourceSet set = rm.GetResourceSet(CultureInfo.CurrentCulture,true,true))
{
UnmanagedMemoryStream s;
s =(UnmanagedMemoryStream)set.GetObject("images/winter.jpg",true);
...
}

使用ResourceManager Class 和ResourceSet Class可以完成其他深层次功能。如下显示资源流中所有嵌入资源的名称。

1
2
3
4
5
6
7
8
9
10
Assembly assembly = Assembly.GetAssembly(this.GetType());
string resourceName= assembly.GetName().Name+".g";
ResourceManager rm = new ResourceManager(resourceName,assembly);
using(ResourceSet set = rm.GetResourceSet(CultureInfo.CurrentCulture,true,true))
{
foreach(DictionaryEntry res in set)
{
MessageBox.Show(res.Key.ToString());
}
}

能够理解资源的类

<Image Source="Images/Blue hills.jpg"/>

代码 C# 完全限定的文件路径

img.Source= new BitmapImage(new Uri(@"d:\Photo\Backgrounds\arch.jpg"));

Relative path

img.Source = new BitmapImage(new Uri("images/winter.jpg",UriKind.Relative));

7.3.3 pack URI

images/winter.jpg

pack://application:,,,/images/winter.jpg

位于其他程序集中的资源

pack://application:,,,/AssemblyName; component/ResourceName

1
2
img.Source= new BItmapImage(
new Uri("pack://application:,,,/ImageLibrary;component/images/winter.jpg"));
1
2
ima.Source= new BitmapImage(
new Uri("ImageLibrary; component/images/winter.jpg",UriKind.Relative));

版本号和公钥

new Uri("ImageLibrary;v1.25;dc642a7f5bd64912;component/images/winter.jpg",UriKind.Relative)

7.3.4 Content Files

1
<MediaElement Name="Sound" Source="Sounds/start.wav" LoadedBehavior="Manual"></MediaElement>

7.4 Localization

7.4.2 为本地化做准备

Ch08 Element Binding

8.1 Binding Elements Together

8.1.1 Binding Expressions

绑定表达式只能用于设置依赖项属性。但是使用OneWayToSource模式可以克服,如果本身是依赖项属性

{} 标记扩展

1
2
3
<TextBlock Margin="10" Text="Simple Text"  Name ="lblSampleText"
FontSize="{Binding ElementName =sliderFontSize,Path=Value}">
</TextBlock>

单向绑定 和双向绑定

1
2
上例子
FontSize = "{Binding ElementName = sliderFontSize,Path=Value,Mode=TwoWay}"

BindingMode Enum:

OneWay

TwoWay

OneTime

OneWayToSource

Default

8.1.4 使用代码创建绑定

1
2
3
4
5
Binding binding = new Binding();
binding.Source = sliderFontSize;
binding.Path = new PropertyPath("Value");
binding.Mode = BindingMode.TwoWay;
lblSampleText.SetBinding(TextBlock.FontSize,binding);

代码移除绑定 ClearBinding() ClearAllBindings()

8.1.5 使用代码检索绑定

1
Binding binding = BindingOperations.GetBinding(lblSampleText,TextBlock.FontSize);
1
BindingExpression expression = BindingOperations.GetBindingExpression(lblSampleText,TextBlock.FontSize);

8.1.6多绑定

8.1.7 绑定更新

UpdateSourceTrigger Enum:

PropertyChanged

LostFocus

Explicit

Default

1
2
BindingExpression binding = txtFontSize.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();

8.1.8 绑定延迟

Delay 让输入时不要随时更新 watch 百度浏览器

1
2
<TextBox Text ="{Binding ElementName =txtSampleText,Path=FontSize,Mode=TwoWay,
UpdateSourceTrigger =PropertyChanged,Delay=500}" Name="txtFontSize"/>

8.2 绑定到非元素对象

需要放弃Binding.ElementName属性,并使用一下属性中的一个

  • Source:
  • RelativeSource:
  • DataContext:

8.2.1 Source属性

最简单的选择

1
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily},Path=Source}"></TextBlock>

alternative

1
2
3
4
<Window.Resources>
<FontFamily x:Key="CustomFont">Calibri</FontFamily>
</Window.Resources>
<TextBlock Text="{Binding Source={StaticResource CustomFont},Path=Source}"></TextBlock>

8.2.2 RelativeSource 属性

1
2
3
4
5
6
7
<TextBlock>
<TextBlock.Text>
<Binding Path="Title">
<RelativeSource Mode="FindAncestor" AncestorType="{x:Type Window}"/>
</Binding>
</TextBlock.Text>
</TextBlock>

合在一起

1
<TextBlock Text="{Binding Path=Title,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}}"></TextBlock>

FindAncestor四种模式

Self

FindAncestor

PreviousData

TemplateParent

8.2.3 DataContext属性

大量元素绑定到同一个对象时使用

使用FrameworkElement.DataContext属性 一次性定义绑定源会更清晰

1
<StackPanel DataContext ="{x:Static SystemFonts.IconFontFamily}"></StackPanel>
1
<TextBlock Margin="5" Text="{Binding Path=Source}"></TextBlock>

Ch09 Commands

WPF 新的命令模型

  • 将事件委托到适当的命令
  • 使控件的启用状态和相应命令的状态保持同步

问题

  1. 命令跟踪
  2. 可撤销的命令
  3. 具有状态并且处于不同“模式”的命令

9.2 WPF命令模型

重要元素

  • 命令:
  • 命令绑定
  • 命令源
  • 命令目标

9.2.1 ICommand接口

WPF命令模型的核心是System.Windows.Input.ICommand接口,定义了命令的工作原理

包含两个方法和一个事件

1
2
3
4
5
6
public interface ICommand
{
void Execute(object parameter);
bool CanExecute(object parameter);
event EventHandler CanExecuteChanged;
}

9.2.2 RoutedCommand Class

using System.Windows.Input.RoutedCommand Class

所有WPF命令都是RoutedCommand类及其派生类的实例

命令是WPF可插入体系架构的主要部分之一

1
2
3
4
public void Execute(object parameter,IInputElement target)
{...}
public bool CanExecute(object parameter,IInputElement target)
{...}

properties

Name OwnerType something

9.2.3 RoutedUICommand class

9.2.4 命令库

常用的命令由以下5个专门的静态类的静态属性提供

  • ApplicationCommands
  • NavigationCommands
  • EditingCommands
  • ComponentCommands
  • MediaCommands

9.3 Excute Command

9.3.1 命令源

触发命令库的命令始终可用。 触发他们最简单的方法是关联到实现了ICommandSource接口的控件,包括ButtonBase类的控件,ListBoxItem Hyperlink MenuItem

ICommandSource 接口定义了三个属性

Command

CommandParameter

CommandTarget

1
<Button Command="ApplicationCommands.New">New</Button>
1
<Button Command="New">New</Button>

9.3.2 命令绑定

仅仅用上面是不够的,被禁用,所以要明确以下三件事情:

  • 当命令被触发时执行什么操作
  • 如何确定命令是否被执行
  • 命令在何处起作用
1
2
3
4
5
6
//Creat the binding.
CommandBinding binding = new CommandBinding(ApplicationCommands.New);
//Attach the event handler.
binding.Executed+= NewCommand_Executed;
//Register the binding
this.CommandBindings.Add(binding);

当单击按钮时,CommandBinding.Executed事件从按钮冒泡到包含元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
<Window x:Class="Commands.herTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="herTestWindow" Height="450" Width="200">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New"
Executed="CommandBinding_Executed"></CommandBinding>
</Window.CommandBindings>

<StackPanel Margin="5">
<Button Padding="5" Command="ApplicationCommands.New">New</Button>
</StackPanel>
</Window>

9.3.3 使用多命令源

1
2
3
4
5
<Menu>
<MenuItem Header="File">
<MenuItem Command="New"></MenuItem>
</MenuItem>
</Menu>

9.3.4 微调命令文本

xaml通过Static 标记扩展完成直接从静态命令对象中提取文本。

1
<Button Command="New" Content="{x:Static ApplicationCommands.New}"></Button>
1
2
<Button Margin="5" Padding="5" Command ="ApplicationCommands.New" Content ="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"
></Button>
1
2
3
<Button Margin="5" Padding="5" Command ="ApplicationCommands.New" ToolTip="{Binding RelativeSource={RelativeSource}={RelativeSource Self},Path =Command.Text}">
<Image.../>
</Button>

9.3.5 直接调用命令

ApplicationCommands.New.Execute(null,targetElement);

9.3.6 禁用命令

1
2
3
4
CommandBinding binding = new CommandBinding(ApplicationCommands.Save);
binding.Executed +=SaveCommand_Executed;
binding.CanExecute +=SaveCommand_CanExecute;
this.CommandBindings.Add(binding);
1
2
3
4
5
<Window.CommandBindings>
<CommandBinding Command ="ApplicationCommands.Save"
Executed="SaveCommand_Executed" CanExecute ="SaveCommand_CanExecute">
</CommandBinding>
</Window.CommandBindings>

9.3.7 具有内置命令的控件

对于简单文本编辑器 添加工具栏按钮,自动获得支持

1
2
3
4
5
<ToolBar>
<Button Command="Cut">Cut</Button>
<Button Command="Copy">Copy</Button>
<Button COmmand="Paste">Paste</Button>
</ToolBar>

在非ToolBar 或者Menu中使用时,就不会获得这项优势

绑定表达式

1
2
3
<Button Command="Cut" CommandTarget="{Binding ElementName = txtDocument}">Cut</Button>
<Button Command="Copy" CommandTarget="{Binding ElementName = txtDocument}">Cut</Button>
<Button Command="Paste" CommandTarget="{Binding ElementName = txtDocument}">Cut</Button>

新的焦点范围 FocusManager.IsFocusScope

1
2
3
4
5
<StackPanel FocusManager.IsFocusScope="True">
<Button Command="Cut">Cut</Button>
<Button Command="Copy">Copy</Button>
<Button COmmand="Paste">Paste</Button>
</StackPanel>

删除命令。。。

9.4 高级命令

9.4.1 自定义命令

实例化一个新的RoutedUICommand对象

范式

1
2
3
4
5
6
7
8
9
10
11
12
13
public class DataCommands
{
private static RoutedUICommand requery;
static DataCommands()
{
InputGestureCollection inputs = new InputGestureCollection();
inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, "Ctrl+R"));
requery = new RoutedUICommand(
"Requery", "Requery", typeof(DataCommands), inputs);
}
public static RoutedUICommand Requery
{ get { return requery; } }
}

9.4.2 未完成

Ch10 资源

对象资源

10.1 资源基础

资源优点

  • 高效
  • 可维护性
  • 适应性

通常在窗口级别定义资源

1
2
3
<Window.Resources>
<ImageBrush x:Key="TeileBrush" TileMode="Tile" ViewportUnits="Absolute" Viewport="0 0 32 32" ImageSource="happyface.jpg" Opacity="0.3"/>
</Window.Resources>

代码访问资源

1
2
3
4
5
private void cmdChange_Click(object sender,RoutedEventArgs e)
{
Button cmd = (Button)sender;
ImageBrush brush = (ImageBrush)sender.FindResource("TileBrush");
}

10.1.6 应用程序资源

如果对象需要被广泛重用,可使用应用程序资源;如果只是在两三个窗口中调用,可以考虑在每个窗口定义。

10.1.7 系统资源

Class: SystemColors SystemFonts SystemParameters

都位于System.Windows名称空间中 另外System.Drawing中有个易混淆的

10.2 资源字典

资源字典的Build Action 设置为Page,这样可以最佳性能 编译为BAML ,设置Resource也是可以的,嵌入程序集,但是解析它的速度要慢一点。

不允许合并使用相同资源名称的资源字典

10.2.3 在程序集之间共享资源

常用方式 将资源字典放置到generic.xaml文件中,并且必须将该文件放到应用程序文件夹的Themes子文件夹中

in generic.xaml

1
2
3
4
5
6
ImageBrush
x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:CustomResources}, ResourceId=SadTileBrush}"
TileMode="Tile"
ViewportUnits="Absolute" Viewport="0 0 32 32"
ImageSource="ResourceLibrary;component/sadface.jpg" Opacity="0.3">
</ImageBrush>

in CustomResources.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace ResourceLibrary
{
public class CustomResources
{
public static ComponentResourceKey SadTileBrush
{
get
{
return new ComponentResourceKey(
typeof(CustomResources), "SadTileBrush");
}
}
}
}

引用方式

xmlns:res=”clr-namespace:ResourceLibrary;assembly=ResourceLibrary”

1
2
3
4
5
6
7
8
9
10
<Button Background="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type res:CustomResources}, ResourceId=SadTileBrush}}"
Padding="5" Margin="5"
FontWeight="Bold" FontSize="14">
A Resource From ResourceLibrary</Button>

<Button Background="{DynamicResource {x:Static res:CustomResources.SadTileBrush}}"
Padding="5" Margin="5"
FontWeight="Bold" FontSize="14">
A Resource From ResourceLibrary
</Button>

Ch11 样式和行为

11.1 样式基础

Style Properties:

Setters

Triggers

Resources

BasedOn

TargetType

1
2
3
4
5
6
7
<Window.Resources>
<Style x:Key="BigFontButtonStyle">
<Setter Property="Control.FontFamily" Value="Times New Roman"/>
<Setter Property="Control.FontSize" Value="18"/>
<Setter Property="Control.FontWeight" Value="Bold"/>
</Style>
</Window.Resources>

11.1.1 创建样式对象

11.1.2 设置属性

如果创建只应用与按钮的样式

1
2
3
4
5
<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="FontFamily" Value="Times New Roman"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="AliceBlue"/>
</Style>

11.1.3 关联事件处理程序

Button.Click win套路

1
2
3
4
5
6
7
8
private void ButtonClick(object sender, RoutedEventArgs e)
{
Button cmd = (Button)e.OriginalSource;
Type type = this.GetType();
Assembly ass = type.Assembly;
Window win = (Window)ass.CreateInstance(type.Namespace + "." + cmd.Content);
win.ShowDialog();
}

11.1.4 多层样式

样式的继承

1
2
3
4
5
6
7
8
9
10
11
12
<Window.Resources>
<Style x:Key="BigFontButtonStyle">
<Setter Property="Control.FontFamily" Value="Times New Roman" />
<Setter Property="Control.FontSize" Value="18" />
<Setter Property="Control.FontWeight" Value="Bold" />
</Style>

<Style x:Key="EmphasizedBigFontButtonStyle" BasedOn="{StaticResource BigFontButtonStyle}">
<Setter Property="Control.Foreground" Value="White" />
<Setter Property="Control.Background" Value="DarkBlue" />
</Style>
</Window.Resources>

但是轻易不要使用样式继承

11.1.5 通过类型自动应用样式

x:Key ="{x:Type Button}"

11.2 Trigger

继承自 System.Windows.TriggerBase的派生类的实例

Trigger

MultiTrigger

DataTrigger

MultiDataTrigger

EventTrigger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Window.Resources>
<Style x:Key="BigFontButton">
<Style.Setters>
<Setter Property="Control.FontFamily" Value="Times New Roman"/>
<Setter Property="Control.FontSize" Value="18"/>
</Style.Setters>
<Style.Triggers>
<Trigger Property="Control.IsFocused" Value="True">
<Setter Property="Control.Foreground" Value="DarkRed"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<Button Style="{StaticResource BigFontButton}">jkjljko</Button>
<Button Style="{StaticResource BigFontButton}">jkjljko</Button>
</StackPanel>

MultiTrigger 提供Conditions集合

11.2.2 事件触发器

简单的动画

使用预先构建的DoubleAnimation Class 位于System.Windows.Media.Animation名称空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<Window.Resources>
<Style x:Key="BigFontButton">
<Style.Setters>
<Setter Property="Control.FontFamily" Value="Times New Roman" />
<Setter Property="Control.FontSize" Value="18" />
<Setter Property="Control.FontWeight" Value="Bold" />
</Style.Setters>

<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="FontSize"
To="22" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="FontSize" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>

</Style.Triggers>
</Style>

</Window.Resources>

<StackPanel Margin="5">
<Button Padding="5" Margin="5"
Style="{StaticResource BigFontButton}"
>A Customized Button</Button>
<TextBlock Margin="5">Normal Content.</TextBlock>
<Button Padding="5" Margin="5"
>A Normal Button</Button>
<TextBlock Margin="5">More normal Content.</TextBlock>
<Button Padding="5" Margin="5"
Style="{StaticResource BigFontButton}"
>Another Customized Button</Button>
</StackPanel>

依赖项属性等于某个特定值时也可以执行动画。~~~~

Ch12 理解形状

形状是元素

  • 形状绘制自身
  • 使用与其他元素相同的方式组织形状
  • 形状支持与其他元素相同的事件

12.1.1 Shape Class

形状都继承自 System.Window.Shapes.Shape

DispatcherObject->DependencyObject->Visual -> UIElement -> FrameworkElement->Shape:

{Rectangle Ellipse Line Polyline Polygon Path}

Properties:

{Fill Stroke StrokeThickness StrokeStartLineCap StrokeEndLineCap StrokeDashArray StokeDashOffset StrokeDashCap StrokeLineJoin StorkeMiterLimit Stretch DefiningGeometry GeometryTransform RenderedGeometry}

12.1.2 矩形和椭圆

如果未设置Stroke 或者Fill属性,形状根本就不会显示

1
2
3
4
5
6
<StackPanel>
<Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="100" Margin="5"
HorizontalAlignment="Left"></Ellipse>
<Rectangle Fill="Yellow" Stroke="Blue" Height="50" Width="100" Margin="5"
HorizontalAlignment="Left"></Rectangle>
</StackPanel>

12.1.5 直线

1
<Line Stroke="Blue" X1="0" Y1="0" X2="10" Y2="100"></Line>

12.1.6&7 折线和多边形

FillRule

:EvenOdd

12.1.8 直线线帽和直线交点

Properties StartLineCap EndLineCap

12.1.9 点划线

12.1.10 像素对齐

通过设置UIElement 类的SnapsToDevicePixels属性为True来启动这个称为像素对齐的特性

12.2 画刷

Classes

SolidColorBrush

LinearGradientBrush

RadialGradientBrush

ImageBrush

DrawingBrush

VisualBrush

BitmapCacheBrush

可以在使用SolidColorBrush画刷的任何时候替代LinearGradientBrush

平铺模式的 TileMode 枚举类型的Tile值

12.3 变换

变换 继承自System.Windows.Media.Transform抽象类的类表示

TranslateTransform

RotateTransform

ScaleTransform

SkewTransform

MatrixTransform

TransformGroup

例如

倾斜形状

重复形状

动画

12.4 透明

12.4.2 透明掩码

12.5 小结

详细分析了WPF对基本二维绘图的支持。首先学习了简单的形状类;然后学习 了如何使用简单和复杂的画刷绘制形状的边框以及填充形状,如何使用变换移动/旋转以及扭曲形状,最后简要介绍 了透明效果。

Ch13 几何图形和图画

13.1 路径和几何图形

抽象类Geometry 有7个派生类

LineGeometry

RectangleGeometry

EllipseGeometry

GeometryGroup

CombinedGeometry

PathGeometry

StreamGeometry

13.1.1 直线 矩形和椭圆图形

1
2
3
4
5
<Path Fill="Yellow" Stroke="Blue">
<Path.Data>
<RectangleGeometry Rect="0,0 100,50"></RectangleGeometry>
</Path.Data>
</Path>

没仔细看

13.3 小结

深入分析了WPF应用程序的2D绘图模型。首先全面介绍了功能最强大的WPF形状类Path。接下来分析了如何使用几何图形构建图画,以及如何使用图画显示无交互功能的轻量级图形。

Ch14 效果和可视化对象

访问低级图形功能,三种WPF技术

  • 可视化对象(Visual)
  • 效果(Effect)
  • WriteableBitmap 类

14.1.1 绘制可视化对象

1
2
3
4
DrawingVisual visual = new DrawingVisual();
DrawingContext dc = visual.RenderOpen();
//画画
dc.Close();

DrawingContext class methods:

DrawLine()

DrawRectangle()

DrawRoundedRectangle()

DrawEllipse()

DrawGeometry()

DrawDrawing()

DrawText()

DrawImage()

DrawVideo()

Pop()

PushClip()

PushEffect()

PushOpacity()

PushOpacityMask()

PushTransform()

掠过

Ch15 Animate

15.1 理解WPF动画

15.1.1 基于时间的动画

15.1.2 基于属性的动画

​ 此为为普通的Windows应用程序添加动态效果的极佳方式

15.2 基本动画

​ WPF使用动画要有相应的动画类

15.2.1 Animation Class

​ 插值动画 和关键帧动画

插值一般命名为DoubleAnimation xxxAnimation 关键帧 是类型名+AnimationUsingKeyFrames 如StringAnimationUsingKeyFrames ObjectAnimationUsingKeyFrames

由于有object

所以所有具有常规动画类的 都支持相应的关键帧动画类

路径动画 DoubleAnimationUsingPath PointAnimationUsingPath

15.2.2 使用代码创建动画

1
2
3
4
5
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.From = 160;
widthAnimation.To = this.Width - 30;
widthAnimation.Duration = TimeSpan.FromSeconds(2);
button.BeginAnimation(Button.WidthProperty, widthAnimation);

From属性对于不清楚宽度的情况时候:widthAnimation.From = cmdGrow.ActualWidth;

不使用To属性时,也可以使用By属性。:widthAnimation.By=10;

IsAdditive属性创建增加数值的动画

Duration.Automatic Duration.Forever.

15.2.3 同时发生的动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void cmdGrow_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.To = this.Width - 30;
widthAnimation.Duration = TimeSpan.FromSeconds(5);
widthAnimation.Completed += animation_Completed;

DoubleAnimation heightAnimation = new DoubleAnimation();
heightAnimation.To = (this.Height - 50)/3;
heightAnimation.Duration = TimeSpan.FromSeconds(5);

cmdGrow.BeginAnimation(Button.WidthProperty, widthAnimation);
cmdGrow.BeginAnimation(Button.HeightProperty, heightAnimation);
}

这两个动画不会同时发生。通常先宽 后高

15.2.4 动画的生命 周期

​ WPF动画并不能真正改变属性的值,只是活动时覆盖。单向动画在运行结束后依然活动,此时改属性值将不起作用。

​ 解决方式

  • 动画设置解决
  • 当动画完成时处理Completed事件删除动画对象

如上的widthAnimation.Completed += animation_Completed;

1
2
3
4
5
6
7
8
private void animation_Completed(object sender, EventArgs e)
{
double currentWidth = cmdGrow.Width;
cmdGrow.BeginAnimation(Button.WidthProperty, null);
cmdGrow.Width = currentWidth;

MessageBox.Show("Completed!");
}

15.2.5 Timeline类

Properties:

  • BeginTime
  • Duration
  • SpeedRatio
  • AccelerationRatio
  • DecelerationRatio
  • AutoReverse
  • FillBehavior
  • RepeatBehavior

15.3 故事板

​ 故事板是BeginAnimation()方法的XAML等价物。通过故事板将动画指定到合适的元素和属性。

​ 事件触发器

15.3.1 故事板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<Window.Resources>
<local:ArithmeticConverter x:Key="converter"></local:ArithmeticConverter>
</Window.Resources>
<Button Padding="10" Name="cmdGrow" Height="40" Width="150"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="{Binding ElementName=window,Path=Width,Converter={StaticResource converter},ConverterParameter=-30}"
Duration="0:0:5"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Height"
To="{Binding ElementName=window,Path=Height,Converter=
{StaticResource converter},ConverterParameter=-50}" Duration="0:0:5"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
<Button.Content>
Click to make me G
</Button.Content>
</Button>

15.3.2 事件触发器

可在如下4个位置定义事件触发器

  • 样式里
  • 数据模板中
  • 控件模板中
  • 元素中

如果需要相对窗口的尺寸设置,而不是硬编码300个单位。需要使用数据绑定表达式

1
2
<DoubleAnimation Storyboard.TargetProperty="Width" To="{Binding ElementName=window,
Path=Width}" Duration="0:0:5"/>

这仍不能得到准确结果,需要构建能够自动完成工作的IValueConverter接口。

Style方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<Window.Resources>
<Style x:Key="GrowButtonStyle">
<Style.Triggers>
<Trigger Property="Button.IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="250" Duration="0:0:5"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Button Padding="10" Name="cmdGrow" Height="40" Width="160" Style="{StaticResource GrowButtonStyle}"
HorizontalAlignment="Center" VerticalAlignment="Center">CLikd</Button>

15.3.3 重叠动画

用BeginStoryboard.HandoffBehavior属性改变处理动画重叠的方式/

推荐一旦动画完成就手动释放动画时钟。

15.3.4 同步的动画

​ 考虑FillBehavior的行为。是否HoldEnd

15.3.5 控制播放

动作类继承自ControllableStoryboardAction类

  • PauseStoryboard
  • ResumeStoryboard
  • StopStoryboard
  • SeekStoryboard
  • SetStoryboardSpeedRatio
  • SkipStoryboardToFill
  • RemoveStoryboard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<Window.Triggers>
<EventTrigger SourceName="cmdStart" RoutedEvent="Button.Click">
<BeginStoryboard Name="fadeStoryboardBegin">
<Storyboard Name="fadeStoryboard" CurrentTimeInvalidated="storyboard_CurrentTimeInvalidated"
SpeedRatio="{Binding ElementName=sldSpeed,Path=Value}">
<DoubleAnimation Storyboard.TargetName="imgDay" Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:10"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>

<EventTrigger SourceName="cmdPause" RoutedEvent="Button.Click">
<PauseStoryboard BeginStoryboardName="fadeStoryboardBegin"></PauseStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdResume" RoutedEvent="Button.Click">
<ResumeStoryboard BeginStoryboardName="fadeStoryboardBegin"></ResumeStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdStop" RoutedEvent="Button.Click">
<StopStoryboard BeginStoryboardName="fadeStoryboardBegin"></StopStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdMiddle" RoutedEvent="Button.Click">
<SeekStoryboard BeginStoryboardName="fadeStoryboardBegin"
Offset="0:0:5"></SeekStoryboard>
</EventTrigger>

</Window.Triggers>
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Padding" Value="5"/>
<Setter Property="Margin" Value="1"/>
</Style>
</Window.Resources>

<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid>
<Image Source="night.jpg"></Image>
<Image Source="day.jpg" Name="imgDay"></Image>
</Grid>

<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
<Button Name="cmdStart">Start</Button>
<Button Name="cmdPause">Pause</Button>
<Button Name="cmdResume">Resume</Button>
<Button Name="cmdStop">Stop</Button>
<Button Name="cmdMiddle">Move to Middle</Button>
</StackPanel>

<TextBlock Grid.Row="2" Name="lblTime" HorizontalAlignment="Center">[[stopped]]</TextBlock>
<Grid Grid.Row="3" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock>Speed:</TextBlock>
<Slider Grid.Column="1" Name="sldSpeed" Minimum="0" Maximum="3" Value="1" TickPlacement="BottomRight"
TickFrequency="0.1" ValueChanged="sldSpeed_ValueChanged"></Slider>



</Grid>
<ProgressBar Grid.Row="4" Margin="0,5,0,0" Height="10" Name="progressBar" Minimum="0" Maximum="1"></ProgressBar>
</Grid>

注意EventTrigger的事件绑定

只能代码方法设置Clock对象检索当前时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void storyboard_CurrentTimeInvalidated(object sender,EventArgs e)
{
Clock storyboardClock = (Clock)sender;
if (storyboardClock.CurrentProgress==null)
{
lblTime.Text = "[[ stopped ]]";
progressBar.Value = 0;
}
else
{
lblTime.Text = storyboardClock.CurrentTime.ToString();
progressBar.Value = (double)storyboardClock.CurrentProgress;
}
}

15.4 动画缓动

线性动画太机械,可以使用曲线动画提高体感。

1
2
3
<DoubleAnimation.EasingFunction>
<ElasticEase EasingMode="EaseOut" Oscillations="10"></ElasticEase>
</DoubleAnimation.EasingFunction>

15.4.3 缓动函数类

每个缓动函数类还提供了EasingMode属性,用于控制是EaseIn EaseOut or EaseInOut

  • BackEase
  • ElasticEase
  • BounceEase
  • CircleEase
  • CubicEase
  • QuadraticEase
  • QuarticEase
  • QuinticEase
  • SineEase
  • PowerEase
  • ExponentialEase

15.4.4 创建自定义缓动函数

Skipppppppppppppppppppppppppp


15.5 Animation Performance

15.5.1 Desired Frame Rate

15.5.2 BitmapCaching 位图缓存

15.6 小结

​ 本章详细分析了WPF动画支持,学习了基本的动画类和线程插值,学习了故事板控制一个或者多个动画的播放,以及如何使用动画缓动创建更趋自然的效果。