《WPF揭秘》读书笔记
1. 类型转换器:例如 SolidColorBrush Color=”White” 之所以可以这样可行,是因为有Color类型转换器来转换”White”字符串,如果没有类型转换器,只能写成,< SolidColorBrush .Color> <Color A=”255” R=”255” G=”255” B=”255”> </SolidColorBrush .Color>
2. 标记扩展:P16,太深奥,还没有看懂!
3. 大多数WPF类指定了一个属性,该属性可以被设置为XML元素中的任何内容。这个属性叫做内容属性。<Button><Button.Content><Rectangle Height =”40” Width=”40” Fill=”Black”></ Button.Content ></Button> 可以写为<Button > <Rectangle Height =”40” Width=”40” Fill=”Black”></Button> 对于Ilist 来说,items 是他的内容属性
4. 运行时加载和解析XAML, Window window=null; using(FileStream fs= new FileStream (“MyWindow.xaml”,FileMode.Open,FileAccess.Read)) {window=(Window)XamlReader.Load(fs)} 假设Window有一个类行为StackPanel的子元素,StackPanel的第5个子对象是一个OK Button。 StackPanel panel=(StackPanel)window.Content; Button okButton =(Button)panel.Children[4];要搜索Window中的子元素可以用FindName (通过按钮名称获得OK按钮)Button okButton=(Button)Window.FindName(“okButton”)
5. x:Class 根元素特性 ,含义:为根元素提供一个派生自元素类型的类,可以在前面加上.NET命名空间作为前缀(可选)
6. x:Key 父元素实现了Idictionary元素的特性 含义:当被添加到父元素的字典里时,请为该项指定键名
7. x:Name 非根元素的特性,但必须与x:Class一起使用 含义:为给元素生成的字段选择一个名称,这样他就可以在过程时被引用
8. x:Null 表示一个空的引用
9. x:Static 引用在过程式代码中定义的任何一个静态的属性,常量或枚举值。在XAML编译后,这也可以是同一个程序集中的非公共成员。如果在默认的命名空间中没有该类型,member字符串必须有XML命名空间前缀
10. 依赖属性:用来实现样式化,自动数据绑定,动画等。他最大的特征是其内建的传递变更通知的能力。变更通知可以重新呈现适当的元素,更新当前布局,刷新数据绑定等。属性触发器可以在属性值改变时执行自定义动作,而不用更改任何的过程式代码 如 IsMouseOver等
11. 属性继承是指属性值自顶向下沿着元素树传递。树下的元素也会被父元素所指定的属性影响。
12. 附加属性是依赖属性的一种特殊形式,可以被有效的添加到任何对象中,如定义在TextElement类中的FontSize和FontStyle。 <StackPanel TextElement.FontSize=”40”,TextElement.FontStyle=”Italic”> PS:从一个按钮事件中获得从Control派生出来的源:Control source=e.Source as Control
13. 3种路由事件策略:管道传递(从根元素向下)冒泡(源元素上触发,一直传递到根元素),直接。传递给事件处理程序的sender参数就是该处理程序被添加到的对象,参数e提供了4个有用的属性:(1)Source:逻辑树中一开始触发该事件的元素。(2)OriginalSource:可视树中一开始触发该事件的元素 (3)Handled 设置为true表示标记事件为已处理,用于停止冒泡和管道事件的标记(4)RoutedEvent 真正的路由事件对象,当一个事件处理程序同时被用于多个路由事件时,他可以有效的识别被触发的事件。事件能够路由就是你在某一个控件上定义的事件可以改变其它地方控件的状态,只是遵照的路径不同而已。
14. 附加事件:类似与附加属性,如:ListBox.SelectionChanged,ButtonClick(有了它一些关于前台改变的触发事件就可以用xaml编写代码完成,需要后台处理的逻辑只需要添加事件处理就行了。例如Button1.Click+=new System.EventHandler(Button1_Click));
15. CommandBinding 可以将要处理的事件与控件绑定起来,来执行Excute指定的事件(当CanExcute返回为true时)当与按钮绑定时CanExcute与IsEnabled同步。
16. 将按键与内建命令绑定<Window.InputBindings><KeyBinding Command=”Help” Key=”F2”/><KeyBinding Command=”NotACommand” Key=”F1”/></Window.InputBindings>
17. 将内建命令绑定到控件 <Button Command=”Cut” CommandTarget=”{Binding ElementName=TextBox}” Content=”Binding RelativeSource={ RelativeSource self} Path=Command.Text> (Cut 可以换成Copy Paste Undo Redo)
18. 对于按钮 ClickMode属性有三个枚举值Release Press Hover 。 RepeatButton是当你做“向上向下”控制数字大小的控件时,可以派上用场。RadioButton有一个可以表示分组的GroupName属性。
19. 设置Label控件的访问键:<Label Target=”{Binding ElementName=”UserBox”}”>_User Name </Label>当按下Alt+U时,TextBox “UserBox”会获得焦点.如果真的要在字符中添加下划线,就用2条连贯的下划线。
20. ToolTip可以控制任何你想要的东西,包括显示按钮,listbox等。ShowDuration控制鼠标悬停在一个元素上多久应该显示ToolTip,InitialShowDisplay控制第一次显示ToolTip的时间间隔
21. 带“头”的容器如GroupBox它的Header可以是任意控件,在它的Header属性里可以设置。
22. Expander和GroupBox很像,它只是包含了一个折叠按钮。他不是基于Win32 UI。
23. Item控件(包括ListBox,Listview等,一个Item控件包括了许多item的集合而不仅仅只是一条内容)
24. XAML中定义数据类型用<sys:DateTime>1/1/2007</sys:DateTime>
25. ItemControl 有一个ItemSource属性,它可以把任意集合赋给Item集合。
26. DisplayMemberPath可以将它设置为每一项上一个属性的名字,由此可以改变所包含的对象的渲染方式。(DisplayMemberBinding似乎也有类似功能,DisplayMemberPath=“Name”类似 DisplayMemberBinding=“{Binding Name}”
27. TextSearch可以控制在一个可编辑的选择框里显示的文本。TextSearch.TextPath可以被附加到ComboBox,把每一项的属性作为选择框选择框的文字使用。TextSearch.TextPath=“Children[1].Children[0].Text” TextSearch的另一个属性Text,他只能应用到每一个item项上,可以选择框内把每一项的Text设置为想选择的文字。<StackPanel TextSearch.Text=”第一项”>
28. SelectionMode 可以改变ListBox对同时选择的操作的支持。要让ListBox水平而不是垂直显示它的内容就要重新定义他的ItemPanelTemple 如:<ListBox.ItemPanel><ItemsPanelTemple><VirtualizingStackPanel Oritation=”Horizontal”></ItemsPanelTemple></ListBox.ItemPanel>
29. ListView有一个View属性,它允许你把视图定义为比ItemPanel更丰富的样子。
30. 设置菜单<Menu><MenuItem Header=”_File”><MenuItem Header=”_OpenFile”><Separator/> ……..
31. ContextMenu是嵌入到元素树中某个元素的Menu
32. ToolBar,StatusBar,RangeBar,Slider的使用。
33. 对于TextBox,当TextBox的宽被限制时,通过设置TextWrapping属性为Wrap或WrapWithOverFlow,可以将文字换成行或额外的行。如果把AcceptReturn设置为true可以通过回车来换行。
34. Margin是指元素边界以外的距离,Padding则是指元素边界以内的。(0)表示四周都是0,(20,5)表示左右20,上下5,(5,10,20,30)左5,上10,右20,下30.
35. Visibility有3个枚举值,Visble,Collapsed(元素不可见且不参与布局),Hidden(元素不可见却参与布局)
36. 2D旋转:LayoutTransform,在对布局以前被应用。RenderTransform在布局后被应用。<Button RenderTransformOrigin=”0.5,0.5”><Button.RenderTransfrom><RotateTransform Angle=”45”>……..
37. 元素的放大缩小:ScaleTransform会从水平,垂直或水平垂直放大或缩小一个元素。<Button.RenderTransform><ScaleTransform ScaleX=”2” ScaleY=”2”>
38. skewTransfrom根据AngleX(角度),AngleY,CenterX(原点),CenterY来实现元素倾斜。
39. 布局:Canvas仅支持用显式的坐标定位元素。右下角按钮<Button Canvas.Right=”0” Canvas.Bottom=”0”>,StackPanel,顺序对他的子元素做一些排列。WrapPanel除了对子元素做堆栈处理外,没有足够的空间来放置一个栈时,会将它封装到行和列中。当WrapPanel有足够的空间,ItemHight与ItemWidth没有设置时,WrapPanel和StackPanel看起来没什么两样。DockPanel只是让元素简单的停靠到面板的某一条边上,然后拉伸元素以填满整个的高度和宽度,最后一个子元素将填满所有的剩余空间。
40. Grid有一个ShowGridLine属性,可以用来调试布局。Grid可以通过GridSplitter来交互改变尺寸。ShareSizeGroup允许多行或多列与其他行或列保持一样的尺寸。
41. 用Grid模拟Cavans,VerticalAlignment=bottom HorizontalAlignment=Right就相当于Canvas.Right=”0” Canvas.Bottom=”0”。Grid同时还可以模拟StackPanel和DockPanel。
42. CliptoBounds控制面板边缘的剪辑内容。
43. ScrollViewr可以控制面板具有滚屏功能。他有2个最重要的属性:VerticalScrollBarVisibility,和HorizontalScrollBarVisibility。它们都有4个枚举值:Visible(总是可见的)Auto(需要时才可见)Hidden(不可见,但任然存在,滚动可以由键盘键来完成)Diabled(不可见也不存在)。
44. ViewBox可以相对于空间缩放元素。它包含Stretch和StretchDirection2个属性。Stretch由4个枚举值(1)None (2)Fill子元素设置为和ViewBox一样的大小 (3)Uniform子元素会在ViewBox内放大到最大,但任然保持自己的长宽比例。(4)UniformToFill 子元素会在保存外观比例的同时,缩放子元素来完全填充ViewBox,但可能ViewBox无法完全显示子元素。StretchDirection有3个枚举值:UpOnly:如果合适,扩大内容,假如内容已经够大,则保持当前的内容大小不变。DownOnly:如果合适,缩小内容,假如内容已经够小,也保持当前内容大小不变。Both:前面的二者兼具。
45. 一个类似于Visual Studio可以收缩,可停靠,可改变尺寸的窗格。见P132
46. WPF应用程序的线程必须跑在单线程单元里(STA),所以Main方法必须标记有STAThread的特性。Show不是一个阻塞的方法(ShowDialog是),调用完Window后就直接返回了。为避免这样的情况,就要写一个消息循环来处理进入的消息,并传递给相应的窗体过程。所以就要调用Application的Run方法。例如Window.Show();app.Run(Window);或者Application app=new Application(); app.StrartUri=new Uri(“MainWindow.xaml”,UriKind.Relative);app.Run();
47. 可以通过修改ShutDownMode值来实现窗口退出,程序却不退出。知道显式的调用ShowDown程序才会退出。
48. Application类的Properties属性可以用来静态的存储数据。例如:app.Properties[“CurrentFileName”]=filename;Application.Current这个静态方法可以获得对当前应用程序实例的引用。; 例如Application.Current.Properties[“CurrentFileName”]=filename;另外一种在页面间传递数据的方式是使用能够接收一个Page实例的Navigate方法,并且在目标页内定义一个能够接收自定义数据的构造函数(可以使用任意多个参数)例如:int PhotoID=10; PhotoPage nextpage=new PhotoPage(PhotoID); this.NavigationService.Navigate(nextpage);对于这项工作 PhotoPage拥有一个如下的构造函数 public PhotePage(int id){LoadPhoto(id);}
49. WPF亦可创建单实例的应用程序:bool mutexIsNew; using(System.Threading.Mutex m=new System.Threading.Mutex(true,uniqueName,out MutexIsNew)){if(MutexIsNew) //这是第一个实例else //这不是第一个实例,退出}
50. 导航和超链结都给实现页间导航。<HyperLink NavigateUri=”PhotoPage.xaml”>here</HyperLink>
51. PageFunction类可以以类型安全的方式把数据返回前一页,并且会自动退回到前一页。(类似与属性设置对话框)可以在VS的Add New对话框添加此页面。
52. .NET可以通过System.Environment.OSVersion来检查操作系统的版本,从而可以针对不同的OS使用不同的技术。例如if(System.Environment.OSVersion.Version.major>=6)//Windows Vista以后的版本用TaskDialog //else 之前用Messagebox
53. 数据绑定可以将任意的.NET对象绑定到一起,并在它们之间建立一条通信通道。C#代码:Binding binding=new Binding(); Binding.source=treeview; binding.path=new PropertyPath(“SelectedItem.Header”); currentFolder.SetBinding(TextBlock.TextProperty,binding); 移除绑定:BindingOperations.clearbinding(CurrentFolder,TextBlock.TextProperty); 用XAML表示:<TextBlock x:Name=”CurrentFolder” Text= “{Binding ElementName=treeview Path=SelectedItem.Header}”> 上面的ElementName可以换成Source,要想在XAML中使用Source,目标对象必须被定义为ResourceDictionary中的某个资源。
54. DisplayMemberPath可以用来渲染Binding(DisplayMemberBinding应该也可以?)
55. IsSynchronizedCurrentItem可以用来同步多个Item,如果在三个ListBox都设定他的属性为true,再将这三个ListBox绑定同一个数据源。那么改变其中一个ListBox,另外2个也会随之改变。
56. 可以用DataContext设置共享源。例如找一个常见的父元素,并设置他的DataContext属性为他的源对象,那么它的子对象会默认绑定这个源对象。
57. 数据模板和值转换器可以定制如何获得数据源值,以及如何显示。<ListBox.ItemTemple><DataTemple><Image Source=”{Binding Path=FullPath}”/>(可以理解成是做了二次绑定)。值转换器是对不兼容的数据类型做桥接。
58. 数据源绑定也可以绑定到方法:假如Photo集合提供了一个叫做GetFolderNam的方法,它需要一个int型参数,返回一个字符串。可以将这个方法定义成一个数据源。如下:<ObjectDataProvider x:key =”DataProvider” ObjectType=”{x:Type local:Photos}” MethodName=”GetFolderName”>< ObjectDataProvider.MothodParameter ><sys:int32 >ncount</sys>< /ObjectDataProvider.MothodParameter ></ObjectDataProvider>
59. BindingMode的四个枚举值:OneWay:当源改变时,目标会被更新。TwoWay:源或目标被改变时,会导致另一方一起被更新。OneWayToSource:OneWay的反响形式,无论何时目标改变时,源都会一起被更新。OneTime:与OneWay一样工作,但源的改变不会反映到目标上,目标会Binding源初始化时的一个快照。
60. 动态资源与静态资源的区别:(1)对资源的更新仅会反映在使用了动态资源的元素上。(2)由于需要跟踪变化,动态资源需要占用更多的资源。另一方面,使用动态资源可以改善加载时间,对静态资源的引用总是发生在Window或Page加载之后,而对动态资源的引用要到实际使用时才会生效。(3)任何静态资源都必须在xaml声明之后才会引用,而动态资源不管引用是否已经定义,都可以使用该元素。
61. <Window.Resource><Image x:Key=”Zoom”/></Window.Resource>……<StaticResource ResourceKey=”Zoom”/>
62. 当将资源存储为应用程序级的资源的时侯,那么可以将他们放入一个独立的xaml文件。一下代码可以将多个资源字典从一些独立的文件总提取并合并出来。<Window.Resource><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source=”file1.xaml”/> <ResourceDictionary Source=”file1.xaml”/> </ResourceDictionary. MergedDictionaries ></ResourceDictionary></Window.Resource>
63. 通过使用一个style,可以添加一个间接层,即在一个地方设置他们,其他每个元素指向这个用于设计的新元素。例如:(定义样式)<style x:Key=”buttonstyle”> <setter property=”Button.Size” value=”22”/> <setter property=”Button.RenderTransform”> <Setter.Value><RotateTransform Angle=”10”/></Setter.Value></style>(使用样式)<Button Style=”{StaticResource buttonstyle}”>1 </Button> 一个style可以从另一个style中继承,通过BasedOn属性。<Style x:Key=”Mystyle” BasedOn=”{StaticResource buttonstyle}”> style也可以在多种元素间实现共享,只需要将上面的Button.Style 改成Control.Style就可以。如果想让style使用在一个特定的类型上,就要使用TargetType属性。<Style x:Key=”Mystyle” TargetType=”{x:Type Button}” ></Style> 对于TargetType,如果你忽略了它的Key属性,它将会应用到所有的目标元素上。
64. 如果要使用已有控件的样式(如ToolBar和Button),则要重载这些样式,<Style x:Key =”{x:Static ToolBar.ButtonStyleKey}” TargetType=”{x:Type Button}”></Style>
65. 触发器分为属性触发器,数据触发器和事件触发器。Style是放置触发器的理想位置。<Style x:Key=”MyStyle” TargeType=”{x:Type Button}”><Style.Triggers><Trigger Property=”IsMouseOver” Value=”True”><Setter Property=”RenderTransform”><Setter.Value><RotateTransform Angle=”10”></Setter.Value></Setter></Trigger></Style.Triggers></Style.Triggles></Style> 属性触发器的一个复杂应用是验证,可以用Validation.HasError属性。 数据触发器可以由任何的.NET 属性出发意外,而不仅仅是.NET属性触发。下面的例子可以TextBlock的Text值来改变它的背景色,当Text为Disabled时,禁用该TextBlock,<Style.Triggers> <DataTrigger Binding=”{Binding RelativeSource ={RelativeSource Self},Path=Text}” Value=”Disabled”> <Setter Property=”IsEnable” Value=”False”/> </DataTrigger> </Style.Triggers> <Setter Property =”Backgroud” Value=”{Binding RelativeSource ={RelativeSource Self}, Path=Text}”> 当此处设置了Value表示只有当Value的取值符合要求时才会被触发。这可能就是数据触发器的用途了。
66. 触发器可以用来表示逻辑或和逻辑与的关系,表示逻辑或则要创建多个完全相同的Setter,表示逻辑与可以使用Trigger的变体叫做MultiTrigger,或者DataTrigger的变体MultiDataTrigger,例如:<Style.Triggers><MultiTrigger> <MultiTriggers.Conditions> <Condition Property=”IsMouseOver” Value=”True”><Condition Property =”IsFocused” Value=”True”/><MultiTrigger.Conditions>……..</Style.Triggers>
67. 模板允许你用任何一个空想出来的东西来代替一个可视的元素树(一个元素模板,可以将它作为资源放到一个单独的控件上)示例:(定义)<Grid.Resource><ControlTemplate x:Key=”ButtonStyle”><Grid>……</Grid></ControlTemplate></Grid.Resource> (使用)<Button Template={StaticResource ButtonStyle}>temp</Button> 模板可以与触发器交互<Grid.Resource><ControlTemplate x:Key=”ButtonStyle”><ControlTemplate.Triggers>….模板也可以用TargetType来限制目标类型。
68. 在模板中使用x:Name命名一个元素不会成为一个能以编程方式访问的成员。但是如果需要以编程的方式访问模板中的一个命名元素,在把模板应用到一个目标以后,就可以使用模板的FindName方法来进行访问。
69. 从控件模板中从模板元素插入属性值的关键是数据绑定,可以用TempleBinding来实现。TempleBinding的数据源总是目标元素,而路径则是目标元素的一个属性值。<Grid.Resource><ControlTemplate x:Key=”ButtonStyle”><Grid><TextBlock Text =”{TempleBinding Button.Content}”></Grid></ControlTemplate></Grid.Resource>
70. ForegroudBrush可以产生一个类似饼图的渐变效果<LinerGradientBrush x:Key=”ForegroudBrush” StartPoint=”0,0 ” EndPoint=”1,1”> <GradientStop offset=”0” Color=”LightGreen”/> <GradientStop offset=”1” Color=”DarkGreen”/> </LinerGradientBrush>
71. 在一个Style内部设置Control的Template属性,然后再将该样式应用到元素更加方便和常用。<Style TargetType=”{x:Type Button}”> <Setter Property=”Template”> <Setter.Value><ControlTemplate TargetType=”{x:Type Button}”>….. </ControlTemplate> </Setter.Value></Setter>