WPF提供了三个用于输入文本的控件:TextBox、RichTextBox和PasswordBox。PasswordBox控件直接继承自Control类。TextBox和RichTextBox控件间接继承自TextBoxBase类。
与前面看到的内容控件不同,文本框能够包含的内容类型是有限的。TextBox控件总是存储字符串(由Text属性提供)。PasswordBox控件也处理字符内容(由Password属性提供),尽管为了减轻特定类型的攻击,它在内部使用SecureString属性。只有RichTextBox控件可存储更复杂的内容:可包含复杂元素组合的FlowDocument对象。
一、多行文本
TextBox控件通常存储单行文本(可通过设置MaxLength属性来限制字符的数量)。然而,在许多情况下需要处理大量内容,从而会希望创建多行文本框。对于这种情况,可将TextWrapping属性设置为Wrap或WrapWithOverflow。如果将TextWrapping属性设置为Wrap,那么总是会在控件的边缘换行,设置将一个特别长的单词放在两行中。如果将TextWrapping属性设置为WrapWithOverflow,这时如果换行算法没有发现合适的位置(如空格或连字符)进行转换行,就允许拉伸某些行使其超出右边缘。
为了能自动在文本框中看到多行文本,需将其尺寸设置的足够大。不应该当设置硬编码的高度(这样不能适应不同的字体大小,而且可能导致布局问题),可使用方便的MinLines和MaxLines属性。MinLines属性是在文本框中必须显示的最小行数。例如,如果MinLines属性值为2,文本框的高度就会增大到至少两行的高度。如果容器的空间不足,部分文本框可能会被裁减掉。MaxLines属性设置文本框能够显示的最大行数。即使扩展文本框使其适合容器(例如,按比例改变尺寸的Grid控件的行或DockPanel中的最后一个元素),也不会超过这一限制。
如果文本框支持换行,用户可输入更多能够立即在可视行中显示的文本。因此,通过将VerticalScrollBarVisibility属性设置为Visible或Auto,添加始终显示或按需显示的滚动条是有意义的(也可设置HorizontalScrollBarVisibility属性来显示不常见的水平滚动条)。
可能希望允许用户在多行文本框中通过按下Enter键输入硬回车(通常,在文本框中按下Enter键将触发默认按钮)。为确保文本框支持Enter键,需要将AcceptsReturn属性设置为true。也可设置AcceptsTabs属性,从而允许用户插入Tab键。否则,Tab键会根据Tab键焦点顺序将焦点移到下一个可得到焦点的控件上。
有时,可能会创建纯粹为了显示文本的文本框。这是,可将IsReadOnly属性设置为true以阻止编辑文本。最好通过将IsEnabled属性设置为false来禁用文本框,因为禁用的文本框会显示变灰的文本,不支持文本选择(也不支持复制到剪切板),并且不支持滚动。
二、选择文本
在任何文本框中都可以通过单击并拖动鼠标,或按住Shift键并使用方向键在文本中移动来选择文本。TextBox类还提供了使用SelectionStart、SelectionLength以及SelectedText属性,通过编程决定选择哪些文本或改变当前所选文本的能力。
SelectionStart属性确定所选文本的开始位置,该位置是从0开始的。例如,如果将该属性设置为10,选择的第一个字符使文本框中的第11个字符。SelectionLength属性指示选中的字符的总数量(0表示没有选中字符)。最后,使用SelectedText属性可快速检查或改变在文本框中选中的文本。可通过处理SelectionChanged事件对文本选择变化加以响应。
<Window x:Class="Controls.TextBoxTest" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="TextBoxTest" Height="300" Width="300"> <Grid Margin="5"> <Grid.RowDefinitions> <RowDefinition Height="2*"></RowDefinition> <RowDefinition Height="*"></RowDefinition> </Grid.RowDefinitions> <TextBox Name="txt" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True" SelectionChanged="txt_SelectionChanged" SpellCheck.IsEnabled="True">The Ministry of Truth contained, it was said, three thousand rooms above ground level, and corresponding ramifications below. Scattered about London there were just three other buildings of similar appearance and size. So completely did they dwarf the surrounding architecture that from the roof of Victory Mansions you could see all four of them simultaneously. They were the homes of the four Ministries between which the entire apparatus of government was divided. The Ministry of Truth, which concerned itself with news, entertainment, education, and the fine arts. The Ministry of Peace, which concerned itself with war. The Ministry of Love, which maintained law and order. And the Ministry of Plenty, which was responsible for economic affairs. Their names, in Newspeak: Minitrue, Minipax, Miniluv, and Miniplenty.</TextBox> <ScrollViewer Foreground="Blue" Grid.Row="1" Margin="0,10,0,5" VerticalScrollBarVisibility="Auto"> <StackPanel> <TextBlock>Current selection:</TextBlock> <TextBlock Name="txtSelection" TextWrapping="Wrap"></TextBlock> </StackPanel> </ScrollViewer> </Grid> </Window>
private void txt_SelectionChanged(object sender, RoutedEventArgs e) { if (txtSelection == null) return; txtSelection.Text = String.Format( "Selection from {0} to {1} is "{2}"", txt.SelectionStart, txt.SelectionLength, txt.SelectedText); }
TextBox类还提供了可控制文本选择行为的属性AutoWordSelection。如果将该属性设为true,那么当在文本中拖动鼠标时文本框每次会选择整个单词。
TextBox控件的另一个有用功能是Undo,该功能允许用户撤销最近的操作。只要未将CanUndo属性设置为false,就可通过代码获得Undo功能(调用Undo()方法),并使用Ctrl+Z快捷获得该功能。
三、拼写检查
TextBox提供了一个更特殊的功能——集成的拼写检查,该功能会在文本中无法识别的单词下面添加偶那个色波浪下划线。用户可右击不能识别的单词,并从可能正确的单词列表中进行选择。
要为TextBox控件启用拼写检查功能,值需设置SpellCheck.IsEnabled依赖项属性即可,如下所示:
<TextBox SpellCheck.IsEnabled="True">...</TextBox>
拼写检查是WPF的特有功能,该功能不依赖与其他软件(如Office)。拼写检查根据为键盘配置的输入语言来决定使用哪个字典。可通过TextBox控件的Language属性重写默认设置,该属性继承自FrameworkElement类,也可在<TextBox>元素中设置xml:lang特性。然而,WPF拼写检查目前只局限于4中语言:英语、西班牙语、法语和德语。可使用SpellingReform属性设置是否将1990年之后对拼写规则的修改应用于法语和德语中。
WPF允许添加一系列被认为没有拼写错误的单词(并将在适当的时候用作右击建议)来自定义字典。为此,必须首先创建词典文件,词典文件不过是具有.lex扩张名的文本文件。在词典文件中添加单词列表。在单独的行中放置每个单词,单词的顺序没有关系。
一旦创建词典文件,确保将TextBox控件的SpellCheck.IsEnabled属性设置为true。最后使用SpellCheck.CustomDictionaries属性关联指向自定义词典的Uri对象。如果选择在XAML中指定Uri对象,那么首先必须导入System名称空间,如下面的示例所示:
<Window x:Class="Controls.CustomSpellChecker" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=system" Title="CustomSpellChecker" Height="300" Width="300"> <Grid Margin="5"> <TextBox SpellCheck.IsEnabled="True" TextWrapping="Wrap" Text="Now the spell checker recognizes acantholysis and offers the right correction for acantholysi"> <SpellCheck.CustomDictionaries> <sys:Uri>pack://application:,,,/Controls;component/CustomWords.lex</sys:Uri> </SpellCheck.CustomDictionaries> </TextBox> </Grid> </Window>
四、PasswordBox
PasswordBox看起来与TextBox类似,但它通过显示圆圈符号字符串来屏蔽实际字符(可通过设置PasswordChar属性选择不同的屏蔽字符)。此外,PassworBox控件不支持剪切板,从而不能复制内部的文本。
与TextBox类相比,PassworBox的用户界面更精简。与TextBox类非常相似,它提供了MaxLength属性;Clear()、Paste()以及SelectAll()方法;并且提供了当文本发生变化时触发的事件(PasswordChanged事件)。TextBox类和PassworBox类最重要的区别在于内部的工作方式。尽管可使用Password属性作为普通字符串读取和设置文本,但在内部PasswordBox类只使用System.Security.SecureString对象。
与普遍文本非常类似,SecureString是纯文本对象。区别是在内存中的存储方式。SecureString以加密方式在内存中保存。用于加密字符串的密钥是随机生成的,存储在一块从来不会写入到磁盘的内存中。最终的结果即使计算机崩溃,恶意用户也不可能通过检查页面文件来检索密码数据。即使找到,也只能找到加密版本。
SecureString类还提供了根据需要丢弃内容的功能。当调用SecureString.Dispose()方法时,内存中的密码数据就会被改写。这样可保证所有密码信息从内存中被改写擦除,并且不能再以任何方式使用。正如所期望的,当控件被销毁时,PassworBox控件会自动为保存在内存中的SecureString对象调用Dispose()方法。