说明:本系列基本上是《WPF揭秘》的读书笔记。在结构安排与文章内容上参照《WPF揭秘》的编排,对内容进行了总结并加入一些个人理解。
文本与墨水控件用来显示与编辑文字。
TextBox (WPF/Silverlight 2.0)
TextBox控件使用户能够输入一行或多行文字。TextBox中输入的内容存储在一个叫Text的字符串属性(string类型)中。要是TextBox支持多行输入,需要给TextBox指定一个高度,或在在没有指定高度的情况下放入一个指定了高度的容器,另外将AcceptsReturn属性为true以允许TextBox接受回车输入。当TextBox接收到回车输入时会在文本中插入一个'\r'。
TextBox绑定了多种命令包括Cut,Copy,Paste,Undo与Redo。
TextBox可以支持拼写检查,方式是将SpellCheck.IsEnabled属性设置为True。TextBox拼写检查的体验类似Office Word,支持的语言由系统所装语言包决定。另外可以使用于TextBlock相同的方式给TextBox的内容设置字体。
TextBox的属性
-
CaretIndex
-
SelectionStart属性:当前选中文本的开始处的索引(由0起)
-
SelectionEnd属性:档期选中文本的结束处的索引
-
SelectionText属性:其用来获取或设置当前选中的文本。
TextBox的事件
-
TextChanged:任何时候Text的内容发生变化都会触发这个事件。
-
SelectionChanged:当选中部分文本变化时触发
-
LostFocus事件:在这个事件处理函数中可以得到最终字符串的内容
TextBox对单行下显示与换行以及多行显示的支持
TextBox宽度除非受周围内容所限或者被指定的值固定,否则TextBox会随着输入文字的增加而逐渐增加(就如一种被撑开的效果)。当TextBox宽度被限制时可以使用如下属性来处理:
TextWrapping:当值为Wrap时,可以将文字形成新的换行,其不允许有任何一行超过文字的边界。当被设置为WrapWithOverflow时,TextBox仅会保留一行,长文字会被截断。
通过将AcceptReturn设置为true可以实现在输入时使用回车来换行。如果通过编程设置给TextBox的字符串包括Text.NewLine这样的字符,则TextBox会换行显示且与AcceptReturn属性无关。
RichTextBox(WPF)
RichTextBox可以支持格式化的文字。RichTextBox与TextBox共有相同的TextBoxBase基类,所以像是TextBox的拼写检查等特性RichTextBox以相同的方式支持。
RichTextBox的属性
- Document:FlowDocument类型,存储着RichTextBox中的内容。
- CaretPosition:TextPointer类型
- Selection:TextSelection类型
PasswordBox (WPF)
PasswordBox是一种设计目的简单的TextBox控件 ,就是用于输入密码。其将输入的文字显示为小圆点(PasswordChar属性提供你更改这种显示的途径),从而保护信息。
PasswordBox不继承自TextBoxBase,所以其不支持除Paste外那些普通TextBox支持的命令,当然更不支持拼写检查。
PasswordBox中输入的值被存储于Password属性中,内部这个值使用System.Security.SecureString类型的对象保存,不同于一般的string,这个对象不会被GC置于托管堆中一段时间,而是会被强行清空。
PasswordBox的事件
- PasswordBox不包含TextChanged与SelectionChanged事件,其定义了一个PasswordChanged事件。
InkCanvas(WPF)
从技术上讲,InkCanvas不是一种控件而是一种元素,它直接由FrameworkElement继承。其行为与控件类似,但是不能通过新的模版改变其样式。InkCanvas用来捕获鼠标或触笔的笔记并绘制在InkCanvas表面。当使用触笔时,笔尖用来写,而另一端用来擦除。
InkCanvas的属性:
-
Strokes:这是一个集合,接受System.Windows.Ink.Stroke类型的对象,这个类型的对象代表一个捕获的笔记。
-
Children:也是一个集合,可以像这个集合中添加任意数量的UIElement元素,这个与Strokes中的元素可以很好在这个Canvas中共存。
-
DefaultDrawingAttributes:改变下一次笔触的外观(粗细,颜色等)。(Stroke也有自己的DrawingAttribute属性,调整这个属性可以独立控制每个笔触线条的样式。)
下面介绍三个InkCanvasEditingMode类型的属性:
-
EditingMode:独立应用到笔尖(或鼠标)
-
EditingModeInverted:应用于控制笔的末端。
-
ActiveEditingMode:返回当前正在被使用的属性。
以上三个属性均为InkCanvasEditingMode类型,可能的值有如下几种:
-
Ink:(EditingMode默认值)通过鼠标或触笔绘画。
-
InkAndGesture:在Ink基础上增加了用户手势的支持,用户手势是System.Windows.Ink.ApplicationGesture美剧类型的值,包括Up,Down,Circle,ScratchOut与Tap。
-
GestureOnly:只识别手势,不绘制用户输入。
-
EraseByStroke:(EditingModeInverted的默认值)当有笔触时,将触点上整条线条擦掉。
-
EraseByPoint:只擦掉笔触实际触及的部分。
-
Select:在笔触及时,选择画笔或任意元素,使他们可以被删除,移动或在InkCanvas范围内调整。
-
None:不响应笔触
当InkCanvas的容器设置为SizeToContent时,如果绘制超出当前边界的内容,容易会自动变大,以适应其中的内容。
WatermarkedTextBox(Silverlight 2.0)
在一些好的界面设计中,我们常会看到文本框中有一些淡淡的提示文字告诉用户应该在这输入什么内容,而当用户开始输入时这些提示就会消失,在Silverlight中使用WatermarkedTextBox可以帮助你轻松实现这个效果。WatermarkedTextBox的使用几乎与TextBox一致,除了你可以通过Watermark属性创建一个简单的水印,另外Watermark属性还是一个内容属性,也就是说可以在水印中放入其他XAML所支持的内容 – 如图片或视频等。
下面代码通过属性元素的语法为WatermarkedTextBox指定了一个复杂的填充水印。
1 <WatermarkedTextBox Width="240"> 2 <WatermarkedTextBox.Watermark> 3 <StackPanel> 4 <Ellipse Width="20" Fill="Azure"></Ellipse> 5 <TextBlock Text="我是测试用的"></TextBlock> 6 <Rectangle Width="50" Height="30"></Rectangle> 7 </StackPanel> 8 </WatermarkedTextBox.Watermark> 9 </WatermarkedTextBox>
提示:
将TextBlock控件的Foreground属性设置为LightGray也可以模拟出类似的水印效果。
InkPresenter控件
通过对Ink的支持,Silverlight将笔输入的功能带入到富Web中。常见的笔输入设备包括:手写笔,触摸屏及传统的鼠标设备。首先我们来看一下支持Ink特性的一些类。每次输入设备划过屏幕时,会生成一个或多个StylusPoint对象,这些对象保存在StylusPointCollection集合中,形成了基本的笔划。这些笔划(StylusPointCollection)又保存在StrokeCollection中组成一组图案。它们可以通过InkPresenter显示出来(InkPresenter是Canvas的子类),同时这些类都提供了属性与方法以供编程操作它们的对象。下面我们详细介绍下这些类及其中提供的方法与属性:
StrokeCollection类型
InkPresenter对象的Strokes集合属性接收StrokeCollection的实例,StroekCollection集合按顺序保存了用户输入的笔画。
属性:
-
Count:当前集合中所有笔画的数量
方法:
-
Add:通过该方法添加一个新的笔画到集合中
-
Clear:用于清除集合中所有的笔画(为了清除Ink会导致界面重绘)
-
GetBounds:返回一个包含所有笔画的矩形边框
-
GetItem(index):通过索引获取一个笔画
-
HitTest:接收一个StylusPointCollection集合,返回此参数与当前StrokeCollection集合相交的笔画的子集。
-
Insert:类似于Add方法,但允许在当前集合指定索引位置插入新的笔画对象。
-
Remove:从StrokeCollection中删除指定的笔画对象
-
RemoveAt:从StrokeCollection中删除指定索引处的笔画对象
Stroke类型
StrokeCollection是Stroke对象组成的集合。一个Stroke对象是一个组成该笔划的点的有序集合,这里笔划是一次独立的动作记录:由笔尖按下,笔尖移动至笔尖抬起。
属性:
-
DrawingAttributes:记录一个笔画独有的高度,宽度,颜色和轮廓颜色。要设置该属性,需要创建一个DrawingAttributes类型的对象并设置其中的属性。
-
StylusPoints:这是一个StylusPointCollection类型的集合,这个集合中包含了组成笔画的StylusPoint对象。
方法:
-
GetBounds:返回包含笔划的矩形边框
-
HitTest:该方法接收一个StylusPointCollection集合,如果任意点与该笔划相交,该方法返回true,否则返回false。
StylusPointCollection类型
该集合包含一组StylusPoint对象,主要用于保存笔划的点集合。(有时候,也可以作为参数传递给HitTest方法,以判断犹如笔划相交)
属性
-
Count:返回集合中点的个数
方法:
-
add:在集合的最后添加新的StylusPoint对象
-
addStylusPoints:通过该方法可以向集合底部添加一个StylusPointCollection对象
-
clear:从集合中删除所有的StylusPoint对象
-
getItem:通过索引获取指定的StylusPoint对象
-
insert:用于向集合的指定位置添加StylusPoint对象
-
remove:用于从集合中删除指定的StylusPoint对象
-
removeAt:用于从集合中删除指定索引的Stylus对象。
StylusPoint类型
StylusPoint代表一个单一的点。
属性:
-
Name:可以使用此属性给一个点命名,名称需唯一。用户输入生成时默认没有名称。
-
PressureFactor:表示用户使用触笔或触屏生成笔画时压力的压力因子,使用鼠标时该压力因子保持默认值。这个值是0到1之间的小数,默认值是0.5。根据压力因子可以编程改变DrawingAttributes以对应压力从而给用户一个很好的反馈。
-
X/Y:这两个属性是笔划的坐标,单位是像素。
Ink相关事件
输入设备的产生的事件按鼠标事件被处理,事件参数为MouseEventArgs类型。该类型提供了如下属性和方法用来查询或处理输入信息,输入设备等。(MoseEnter,MouseLeave,MouseLeftButtonDown,MouseLeftButtonUp和MouseMove事件接收相同的MouseEventArgs对象)
属性:
-
ctrl:布尔类型,事件触发时用户是否按着Ctrl键。
-
shift:布尔类型,事件触发时用户是否按着Shift键。
方法:
-
GetPosition:当不给该方法传递参数时,返回鼠标相对于触发事件的元素的位置。如果传入一个界面元素,则返回鼠标相对于该元素的位置。
-
GetStylusInfo:返回一个包含笔尖状态信息的StylusInfo对象。该对象包含如下两个属性:
-
IsInverted:布尔值,表示笔是否被倒转,当为true,即笔倒转表示用户希望擦出内容
-
DeviceType:返回设备类型 – 鼠标,触笔或触屏。
-
-
GetStylusPoints:类型为StylusPointCollection,包含最后一次鼠标事件所收集到的点的拷贝。
我们可以使用JavaScript或C# 来操作这些类及其对象,首先我们看一下使用JavaScript捕获用户输入并通过InkPresenter展示的方法:
第一步我们需要初始化一些基本的对象:
1 var theInk; //Ink Presenter 2 var stroke; // a Stroke 3 var slCtrl; // Silverlight control 4 function handleLoad(control, userContext, rootElement) { 5 slCtrl = control; 6 theInk = control.content.findName("inkPr"); 7 }
一切就绪,我们开始由MouseLeftButtonDown事件开始一步步展示捕获过程。
1 function inkMouseDown(sender, args) { 2 theInk.CaptureMouse(); 3 stroke = slCtrl.content.createFromXaml('<stroke/>'); //create stroke 4 var da = slCtrl.content.createFromXaml('<DrawingAttributes/>'); 5 stroke.DrawingAttributes = da; 6 stroke.DrawingAttributes.Width = 2; 7 stroke.DrawingAttributes.Height = 2; 8 stroke.DrawingAttributes.Color = "White"; 9 stroke.DrawingAttributes.OutlineColor = "White"; 10 //add styluspoint to stroke 11 stroke.StylusPoints.AddStylusPoints(args.GetStylusPoints(theInk)); 12 //add stroke to inkpresenter 13 theInk.Strokes.add(stroke); 14 }
上面方法中,我们开始捕获鼠标并定义了表示线条样式的DrawingAttributes对象,接下来处理鼠标的移动,这个过程中记录鼠标的轨迹并绘制在InkPresenter中:
1 function inkMouseMove(sender, args) { 2 if (stroke != null) { 3 stroke.StylusPoints.AddStylusPoints(args.GetStylusPoints(theInk)); 4 } 5 }
最后,我们处理鼠标抬起事件,我们清空stroke,这样鼠标移动的点信息不会再添加到笔划中:
1 function inkMouseUp(sender, args) { 2 stroke = null; 3 theInk.releaseMouseCapture(); 4 }
看过了JavaScript的示例,接着我们给出一段使用C#实现这个效果的代码:
1 Stroke newStroke; 2 private void inkEl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 3 { 4 inkEl.CaptureMouse(); 5 // Create a new stroke. 6 newStroke = new Stroke(); 7 DrawingAttributes da = new DrawingAttributes(); 8 newStroke.DrawingAttributes = da; 9 newStroke.DrawingAttributes.Width=2; 10 newStroke.DrawingAttributes.Height=2; 11 newStroke.DrawingAttributes.Color=Colors.White; 12 newStroke.DrawingAttributes.OutlineColor=Colors.White; 13 newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkEl)); 14 inkEl.Strokes.Add(newStroke); 15 } 16 private void inkEl_MouseMove(object sender, MouseEventArgs e) 17 { 18 if (newStroke != null) 19 { 20 newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkEl)); 21 } 22 23 } 24 private void inkEl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 25 { 26 newStroke = null; 27 inkEl.ReleaseMouseCapture(); 28 }