【翻译】Pro.Silverlight.5.in.CSharp.4th.Edition - 第五章 元素 03

目录:点击这里

上一篇:【翻译】Pro.Silverlight.5.in.CSharp.4th.Edition - 第五章 元素 02

条目控件Items Controls

包含了条目集合的控件一般继承于ItemsControl类。Silverlight提供了4个基于列表的控件。本章节中我们会学习一下ListBox、ComboBox和TabControl,之后在第21章我们会学习TreeView控件。

      ItemsControl类涵盖了所有基于列表的控件都使用到的基本要素。尤其是它提供了两种填充条目的方式。最直接的方式是用代码或者在XAML中直接将条目添加到Items集合中。这种方式本章很快会讲到。不过,如果想显示一个动态的列表,一般都是用数据绑定的方式来处理。这种情况下是将ItemsSource属性设置为我们要显示的数据条目的集合。这第二种方式将会在第20章中具体介绍。

列表框ListBox

我们可以通过在ListBox元素中嵌套多个ListBoxItem元素的方式来给列表框添加条目。比如,下面这段示例XAML就是一个包含了几个颜色的列表的ListBox:

<ListBox>
  <ListBoxItem Content="Green"></ListBoxItem>
  <ListBoxItem Content="Blue"></ListBoxItem>
  <ListBoxItem Content="Yellow"></ListBoxItem>
  <ListBoxItem Content="Red"></ListBoxItem>
</ListBox>

        还记得我们在第2章说过,不同的控件嵌套子元素的方式也不一样。此处可看出来,ListBox是通过Items集合来存储每个嵌套的对象。


  备注:如果将SelectionMode属性设置为Multiple或Extended,那么ListBox将会支持多选。在Multiple模式下,我们是通过点击条目来设置该条目被选中或者取消选中;而在Extended模式下,我们是通过按住Ctrl键再通过点击条目来选择,或者通过按住Shift键来选择相连的一系列条目。无论是那种模式,最终我们都是用SelectedItems这个集合属性(而不是SelectedItem属性)来获取所有选中的条目。


      ListBox是一个极为灵活的控件。其子元素集合不仅仅限于ListBoxItem对象,可以是任何元素。这能够正常运行是因为ListBoxItem类继承于ContentControl,也就是说ListBoxItem能够内嵌一个内容。如果这个内嵌的内容是继承于UIElement类的子类,那么,那么这个内嵌内容将会在ListBox中渲染并且呈现出来。另一方面,如果这个内嵌的内容是其它的一些类型,那么ListBoxItem会调用ToString()方法,并且显示出其最终的结果文本。

      比如说,我们现在打算创建一个由图片组成的清单,那么对应的XAML标记可能如下所示:

<ListBox>
  <ListBoxItem>
    <Image Source="happyface.jpg"></Image>
  </ListBoxItem>
  <ListBoxItem>
    <Image Source="happyface.jpg"></Image>
  </ListBoxItem>
</ListBox>

       ListBox其实足够机智,因为它会按照自身的需要暗中创建ListBoxItem对象。这意味着我们可以直接将我们需要显示的对象放在ListBox的元素中。下面这个更花哨的示例是使用内嵌的StackPanel对象将文本和图片内容组合在一起。

<ListBox>
  <StackPanel Orientation="Horizontal">
    <Image Source="happyface.jpg" Width="30" Height="30"></Image>
    <TextBlock VerticalAlignment="Center" Text="A happy face"></TextBlock>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <Image Source="redx.jpg" Width="30" Height="30"></Image>
    <TextBlock VerticalAlignment="Center" Text="A warning sign"></TextBlock>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <Image Source="happyface.jpg" Width="30" Height="30"></Image>
    <TextBlock VerticalAlignment="Center" Text="A happy face"></TextBlock>
  </StackPanel>
</ListBox>

 

       本例中,StackPanel成为了被ListBoxItem所包含的子条目。最终运行效果如图5-11所示。

图5-11 图片列表

      列表框的条目可以嵌套任意元素这一特性使得我们可以不需要使用特定的类创建各种基于列表的控件。比如,我们可以通过在ListBox中嵌套一个CheckBox元素,这样运行的时候会看到每个条目的开头会有一个复选框。

      如果列表的条目类型不是默认的ListBoxItem,那么一定要注意有个必须要知道的关键点:在读取SelectedItem值(或者是SelectedItems、Items集合)的时候,所得到值的类型并不是ListBoxItem类型,而是我们在列表中所放置的对象的实际类型。用前面那个例子来说,这个类型就是StackPanel。

      在手动将条目放入列表中的时候,由开发人员自行决定是直接将条目放入还是将条目用ListBoxItem对象做一次包装再放入。第二种方式虽然代码稍长,但通常来说能保持代码的干净。无论如何,最重要的是要保证其一致性。比如,如果我们在列表中放置的是StackPanel对象,那么ListBox.SelectedItem对象就会是StackPanel;如果是将StackPanel用ListBoxItem进行包装后再放入列表,那么ListBox.SelectedItem对象就是ListBoxItem,与之关联的代码也相应的处理。另外,还有第3种选择——将数据对象集合放在ListBox中,然后使用数据模板来显示我们要显示的属性。这种技术会在第20章讨论。

      使用ListBoxItem比直接使用嵌套对象多了一点额外的功能——也就是ListBoxItem定义了一个IsSelected属性(这个属性是可读写的)、一个Selected和一个Unselected事件。不过,我们可以通过ListBox类的一些成员(比如SelectedItem属性、SelectedIndex属性和SelectionChanged事件)实现相似的功能。


备注:ListBox支持虚拟化(virtualization),因为它使用VirtualizingStackPanel(虚拟化堆栈面板)来对条目进行布局。这意味这ListBox只对当前显示出来的条目创建ListBoxItem对象,这样就能实现在性能没有明显降低的情况下展示条目数成千上万的列表。当用户操作滚动条的时候,已存在的那组ListBoxItem对象将会被重用,并且使用不同的数据来展示当前的条目。列表控件不支持虚拟化(包含出了ListBox和DataGrid意外的其它控件),这样当所有的数据条目都抓取出来的时候,数据的加载滚动将会法特别慢。


组合框ComboBox

ComboBox和ListBox控件有一些类似。它包含一个ComboBoxItem集合对象,这个对象可以间接创建,也可以直接创建出来。和ListBoxItem一样,ComboBoxItem也是一个内容控件,可以包含任何嵌套元素。这个组合框和Windows中的复选框不一样,我们无法在Silverlight的ComboBox中用键盘输入内容来实现对条目的选取或者编辑选中值。我们只能通过鼠标或者键盘的方向键来处理这些问题。

      ComboBox和ListBox的关键区别是它们自身呈现的方式。ComboBox控件采用了下拉式列表的方式,这意味着ComboBox的条目一次只能选择一项。

      ComboBox有一个有意思的现象:当我们使用自动尺寸模式的时候,它会自己修改自身的尺寸。ComboBox会增大其宽度以适应当前内容,这意味着在更换选中元素的时候控件的宽度会随之发生变化。不过遗憾的是,目前没有合适的方法能告知控件其子元素的最大宽度。因此,我们现在只能通过硬编码的值来设置Width属性。

      Silverlight 5 针对ComboBox有一个小幅的改进:支持输入提示特性。在这个特性的帮助下,我们可以通过键入某条目名称的前面几个字母就直接跳转到该项目。这个特性在下拉列表框开放或者关闭的时候都可以正常运行,尽管开放的时候更简单(因为可以看到所有的条目列表)。比如,想象一个包含了两个条目的列表,这两个条目都是以E字母作为开头——Elephant和Elevator。如果用户输入的是E,Silverlight会自动选择第一个条目(Elephant),而当用户输入了“Elev”的时候,选择项就会跳到下一个条目(Elevator)。


备注:ComboBox的输入提示特性让用户通过键盘来选择一个条目,这是个非常基本的快捷操作。如果需要更强大的自动完成功能,比如能够对匹配的规则进行控制,甚至能从web服务中采集到一个动态的输入建议的清单——面对这样的需求,就需要使用本章后面内容将会介绍到的AutoCompleteBox控件。


 选项卡TabControl

我们肯定都会选项卡这种控件特别熟悉了:这种一种非常方便的工具,可以通过一系列选项卡式的页面将大量的内容整合在一个容器中。在Silverlight中,TabControl是一种条目控件,它可以包含一个或者多个TabItem元素。

      和其它特定的Silverlight控件一样,TabControl也是定义在一个单独的程序集中。当我们在页面中使用这个控件的时候,VS会增加一个System.Windows.Controls.dll程序集的引用,并且映射相应的XML命名空间,就像这段标记:

<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
... >

       使用TabControl的时候,我们得在这个控件内增加一个或者多个TabItem元素。每个元素都可以代表一个独立的页面。由于TabItem是内容控件,因此它可以用另一个Silverlight元素(比如布局容器)作为它的子元素。

      下面这个XAML标记是一个包含了两个卡片页的TabControl,第一个卡片页的内容是一个包含了三个复选框的StackPanel,如下所示:

<controls:TabControl>
  <controls:TabItem Header="Tab One">
    <StackPanel Margin="3">
      <CheckBox Margin="3" Content="Setting 1"></CheckBox>
      <CheckBox Margin="3" Content="Setting 2"></CheckBox>
      <CheckBox Margin="3" Content="Setting 3"></CheckBox>
    </StackPanel>
  </controls:TabItem>
  <controls:TabItem Header="Tab Two">
  ...
  </controls:TabItem>
</controls:TabControl>

 

      TabItem用TabItem.Content属性来存储它的内容(本例中是StackPanel)。有趣的是,TabItem还有另外一个可以存储任何内容的属性:Header。上面这个例子中,Header存储的是一个简单的文本字符串。我们可以很容易将图形内容或者内置了各种元素的布局容器作为Header的内容值,如下所示:

<controls:TabControl>
  <controls:TabItem>
    <controls:TabItem.Header>
      <StackPanel>
        <TextBlock Margin="3">Image and Text Tab Title</TextBlock>
        <Image Source="happyface.jpg" Stretch="None" />
      </StackPanel>
    </controls:TabItem.Header>
    <StackPanel Margin="3">
      <CheckBox Margin="3" Content="Setting 1"></CheckBox>
      <CheckBox Margin="3" Content="Setting 2"></CheckBox>
      <CheckBox Margin="3" Content="Setting 3"></CheckBox>
    </StackPanel>
  </controls:TabItem>
  <controls:TabItem Header="Tab Two">
  ...
  </controls:TabItem>
</controls:TabControl>

       图5-12展示了这段XAML的运行结果。

图5-12 另类风格的卡片页标题

      和ListBox一样,TabControl也包含SelectionChanged事件,在改变卡片页的选择的时候会触发。另外它也包含SelectedIndex和SelectedItem这两个属性,用这两个属性我们就可以读取或者设置当前卡片页项。TabControl还有一个自身特有的TabStripPlacement属性,这个属性可以用于设置将选项卡的标签放置在控件的侧边或者底部(默认是在顶部)。

文本控件 Text Controls

Silverlight包含一个标准的TextBox控件和一些特定的继承于TextBox的控件,包括PasswordBox(用于输入私密内容)、AutoCompleteBox(在用户输入的时候会显示一个建议输入的下拉列表)、RichTextBox(支持丰富的格式文本、链接和图片等)。在接下来的章节中我们会陆续介绍这些控件。

文本框TextBox

TextBox这个基础控件存储的是字符串,由Text属性所提供。我们可以使用TextAlignment属性来设置文本的对齐方式,另外我们也可以使用表5-2所列出的所有属性来对文本框中的文本字体进行设置。TextBox也支持Windows体系中的一些特性,包括滚动、文本换行、剪贴板的剪切和粘贴和文本选取。

      一般情况下,TextBox控件存储一个单行文本。(我们可以通过MaxLength属性来限制输入字符的数量。)不过,有两种方式可以将文本分为多行。第一种方式是将TextWrapping属性设置为Wrap;第二种方式是AcceptsReturn属性设置为true,这样用户按下回车的时候就可以换行了。

      有时候我们创建的文本框仅仅是为了显示文本,这种情况,我们可以将IsReadOnly属性设置为true就能够禁止文本的编辑,这种方式比将IsEnabled设置为true的禁用控件效果要好,因为后者会使得文本呈灰色状态(这样看起来费劲),而且不支持文本的选取(也就无法将文本复制出来),另外如果文本的长度超过文本框的长度会使得超出的部分看不到。

    正如我们所知的,我们可以通过鼠标的点中后拖拽或者键盘上的方向键和Shift键的组合来在文本框中对文本进行选取。TextBox控件也给我们提供了SelectionStart、SelectionLength和 SelectedText这3个属性可以让我们通过编程的方式来读取或者设置选取的文本。

      SelectionStart标识选择文本的起始位置,其值是从0开始。比方说,如果将这个属性设置为10,那么文本框中的文本选择将从第11个字符开始。SelectionLength标识所选文本的总字符数。(如果值为0,那么表示没有选择文本。)最后SelectedText这个属性标识所选择文本的内容。

      我们通过处理SelectionChanged这个事件来对所选文本的变化做出响应。下面这段示例代码实现的功能就是对这个事件做出响应并且将当前所选择的内容显示出来:

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);
}

       图5-13展示了运行的结果。

图5-13 文本的选取

和剪贴板的一些交互函数

Silverlight的System.Windows命名空间下有一个Clipboard类,它提供了三个和Windows剪贴板相关的静态方法:

  • GetText():获取剪贴板当前的Unicode文本信息(字符串)。剪贴板上的其他类型的数据,比如图片或者文件,这些是不可用的。
  • SetText():将所设置的文本字符串粘贴进剪贴板。
  • ContainsText():如果剪贴板中包含Unicode文本,则此方法返回true。

只能通过用户发起的动作(比如鼠标的点击或者键盘按键)才能响应剪贴板的相关方法。在首次执行到GetText()或者SetText()方法的时候,系统会弹出一个是否允许应用程序访问客户端电脑的剪贴板的确认对话框。如果用户选择了Yes,那么本次session不会再弹出这个对话框(但是下次应用程序运行并再尝试访问剪贴板的时候还是会弹出这个消息)。如果用户点击No,那么GetText()和SetText()方法会抛出SecurityException异常,这个可以在代码中捕获到。

密码输入框PasswordBox

Silverlight中包含一种单独的专门用于处理密码输入的控件,名叫PasswordBox。它外观和TextBox差不多,不过所显示的文本则是某一个字符的循环字符串,用以将真实的输入内容掩盖住。我们可以通过PasswordChar这个属性来设置显示字符串,通过Password属性来设置真实的输入文本。PasswordBox并没有提供Text属性。

      另外,PasswordBox不支持剪贴板。这意味着用户无法使用快捷键将控件中的内容复制出来(靠,真的假的,我咋在SL4里头发现不是这样呢==),另外,PasswordBox也无法使用像SelectedText这样的属性。


备注:WPF中的PasswordBox使用的是内存中加密的机制,可以保证密码信息不会被某些类型的漏洞(比如内存转储)所利用而捕获到。而Silverlight的PasswordBox不具备这个特性,它只是单纯地存储控件上的内容信息,就像普通的TextBox的那种处理方式一样。


自动完成框AutoCompleteBox

AutoCompleteBox控件相当于一个文本输入和一个建议输入的下拉列表的组合控件。在Web中,这个特性是个非常常见的技术,比如在谷歌主页中的查询框中输入信息后就下拉展示出一些相关的可能的查询内容。

      在Silverlight中这个控件的功能非常强大,它提供了好几种方式来决定下拉列表应该展示什么条目内容。最简单的方式是用普通的AutoCompleteBox作为开头就了事:

<input:AutoCompleteBox x:Name="txtMonth"></input:AutoCompleteBox>

      当我们从工具箱中将AutoCompleteBox控件拖进设计页面的时候,VS会自动创建一个名为input的XML别名:

<UserControl xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input" ... >

     加上了AutoCompleteBox控件之后,就使用数组或者列表的形式创建一个建议输入的列表集合(元素的顺序无所谓),然后将这个集合应用于AutoCompleteBox控件的AutoCompleteBox.ItemsSource属性上。典型的做法是在页面首次加载的时候在页面的构造函数或者UserControl.Loaded事件中完成这个步骤。

      下面这个示例是使用12个月份字符串作为建议输入的集合:

string[] monthList = {"January", "February", "March", "April",
  "May", "June", "July", "August", "September",
  "October", "November", "December"};
txtMonth.ItemsSource = monthList;

       这些代码就足够实现默认的功能了。当用户在输入框中敲入字符的时候,就会出现一个潜在的与之匹配的下拉列表,而且是按照字母顺序排列的(如图5-14)。我们通过鼠标点选或者上下箭头选择我们需要的项,这样就达到了避免手工输入整个内容的目的。


备注:AutoCompleteBox虽然提供了建议输入的列表,但是控件并没有强制用户不可以输入列表中不存在的内容。想强迫用户只能选择建议列表中的项可没有什么简单的办法。


      还有另一个方式可以控制AutoCompleteBox的行为。如果将IsTextCompletionEnabled属性设置为true,那么在用户输入的时候,控件会自动完成剩余的输入内容。用刚才的月份示例来说,如果用户输入了“J”,那么控件会寻找建议列表中第一个匹配“J”的条目(也就是“January”),然后自动补充上后面的“anuary”。而且新输入的内容呈现高亮选中模式,这表示用户继续输入内容可以将这些内容直接覆盖掉(也可以按删除键或者退回键将这些内容直接删掉。)图5-14展示了有无设置这个属性的不同效果。


备注:通过AutoCompleteBox.Text属性我们可以读取到控件当前所显示的文本内容。如果IsTextCompletionEnabled属性设置为true,那么控件自动补充的部分也会读取到。


图5-14 以“J”开头的月份输入

筛选模式

默认情况下,AutoCompleteBox是通过以当前所输入内容作为开头这个条件来进行建议输入的匹配筛选。不过,我们可以通过FilterMode属性改变这种筛选行为。FilterMode可以选择的值的来源是AutoCompleteFilterMode枚举。表5-4展示了最常用的一些枚举值。

5-4 AutoCompleteFilterMode枚举值列表

名称

说明

None

不进行筛选,数据源的所有元素都会作为建议输入显示在列表中。当我们自己在开发的过程需要获取元素集合的时候就会使用这个选项。(比如需要从数据库中查询或者从web服务发起请求获取。)

StartsWith

筛选出以所输入的内容作为开头的所有条目。这个值也是默认值。

StartsWithCaseSensitive

筛选出以所输入的内容作为开头的所有条目,额外限制是区分大小写。

Contains

筛选出包含所输入的内容的左右条目。比如输入“ember”,那么September、November和December都会作为建议输入。

ContainsCaseSensitive

筛选出包含所输入的内容的左右条目,额外限制是区分大小写。

Custom

必须通过TextFilter或者ItemFilter属性自定义筛选条件。实际上,如果设置了TextFilter或者ItemFilter属性,那么控件就会自动切换为Custom模式。

 自定义筛选

要实现自定义筛选,就必须设置TextFilter或者ItemFilter属性。如果ItemsSource是字符串集合,就使用TextFilter;如果是某种对象集合,那就使用ItemFilter。无论哪种方式,TextFilter或者ItemFilter属性都是指向创建的自定义筛选方法的一个委托。这个自定义筛选方法有两个参数:用户输入的文本字符串和当前要检测是否匹配的条目。

public bool ItemFilter(string text, object item)
{ ... }

      此方法中的代码要实现的功能是:在我们既定的匹配逻辑基础上,如果当前条目应该属于建议输入下拉列表中的一项,那么方法返回true;否则返回false,将此条目从下拉列表中忽略掉。

      当碰到建议输入列表是结构很复杂的对象集合的时候,自定义筛选显得尤其有用。因为它可以让我们将对象的不同属性组合在一起进行筛选。

      比如假设有如下一个简单的Product类:

public class Product
{
  public string ProductName { get; set; }
  public string ProductCode { get; set; }
  public Product(string productName, string productCode)
  {
    ProductName = productName;
    ProductCode = productCode;
  }
  public override string ToString()
  {
    return ProductName;
  }
}

 

      现在打算创建一个AutoCompleteBox控件,实现用户在此控件中输入的时候能和Pr oduct对象进行匹配筛选。首先的准备条件是要给AutoComplexBox.ItemsSource这个属性赋值为Product对象的集合:

Product[] products = new []{
  new Product("Peanut Butter Applicator", "C_PBA-01"),
  new Product("Pelvic Strengthener", "C_PVS-309"), ...};
acbProduct.ItemsSource = products;

       如果到此为止不再做其它设置,那么AutoCompleteBox会按照其默认的标准行为来执行:当用户输入的时候,控件会对每个Product对象调用ToString(),然后 返回值字符串作为建议输入的筛选数据源。由于Product类复写ToString()方法,将ProductName作为方法的返回值,这样AutoCompleteBox就会将用户输入的内容和产品名称进行匹配筛选,当然这么处理合情合理。

      不过,如果我们用自定义筛选的方式来处理,那么最后实现的效果可能更人性化。比如,我们可以检查用户输入的是否匹配ProductName属性或者匹配ProductCode属性,换句话说就是想整个Product对象作为匹配的检测对象。下面这段示例代码展示这个技巧的使用方法:

public bool ProductItemFilter(string text, object item)
{
  Product product = (Product)item;
  //检查所输入的内容是否属于产品代码的一部分或者是产品名称的开头字符串
  return ((product.ProductName.StartsWith(text)) ||
    (product.ProductCode.Contains(text)));
}

       我们只需要在控件首次初始化的时候将这个方法应用于控件即可:

acbProduct.ItemFilter = ProductItemFilter;

       现在,如果用户输入“PBA”,由于这个字符串匹配上了产品代码“C_PBA-01”,因此“Peanut Butter Applicator”这一项就作为建议输入列表的一个条目出现在下拉列表中。如图5-15所示。

图5-15 自定义筛选匹配产品代码

动态条目列表

到目前为止,我们学习了使用ItemsSource属性来给AutoCompleteBox设置建议输入的集合。为了保证正常运作,我们必须有一个完整的列表,而且此列表的大小必须在可控范围内。如果我们必须从其他地方采集信息,又或者这个列表太大以至于无法一次性加载完整个数据,那我们就得用另一种途径来填充AutoCompleteBox的数据源了。这种情况下,就不能在页面首次加载的时候直接设置ItemsSource属性——我们需要在运行时用户输入的时候动态设置这个属性。

      要按照这个方式来做,首先需要将FilterMode属性设置为None,然后要处理Populating事件。每当控件准备查询筛选结果的时候就会触发Populating事件。默认情况下,每次用户按键或者改变当前文本内容的时候,这个事件就会触发。我们可以使用MinimumPrefixLength和MinimumPopupDelay这两个后面会提到的属性让匹配行为更贴合实际。

<input:AutoCompleteBox x:Name="acbProducts" FilterMode="None"
  Populating="acbProducts_Populating" ></input:AutoCompleteBox>

       当Populating事件激活的时候,我们有两个选择:立刻设置ItemsSource属性或者启动异步进程来处理。如果当前已经有了建议输入的列表或者这个列表数据能够很快生成,那么我们可以采用立刻设置ItemsSource属性的方式,建议输入的列表会很快出现在下拉列表中。

      然而,大多数情况下,我们都必须经过一个可能耗时较长的步骤后才能得到建议输入的列表,比如执行了一系列的计算工作或者通过web服务之后才获取到数据。这种情况下,我们需要使用异步的方式来处理。尽管我们可以通过多线程(第16章)来完成这个工作,不过我们并不是只能这样做。有一些Silverlight特性已经内置了异步特性——比如Web服务,这就是一种纯粹使用异步调用的技术。

      当使用异步操作的时候,我们必须明确将Populating事件处理程序中的正常进程取消,即将PopulatingEventArgs.Cancel属性设置为true。然后便可以启动操作。下面这个示例展示了如何通过web服务来异步地获取建议输入的列表。(在第19章中我们会更细致地介绍web服务相关的技术。现在,我们只是从大概来认识一下这个技术点。)

private void acbProducts_Populating(object sender, PopulatingEventArgs e)
{
  // 标识即将开始准备异步的任务
  e.Cancel = true;
  // 创建web服务对象
  ProductAutoCompleteClient service = new ProductAutoCompleteClient();
  // 注册相应的完成事件
  service.GetProductMatchesCompleted += GetProductMatchesCompleted;
  // 异步调用web服务
  service.GetProductMatchesAsync(e.Parameter);
}

       在相应的web服务器上,对应的GetProductMathes()web方法将会运行返回相关的匹配信息:

public string[] GetProductMatches(string inputText)
{
  // GetProducts()方法实现获取产品信息 (比如从数据库中)
  Product[] products = GetProducts();
  // 创建匹配集合
  List<string> productMatches = new List<string>();
  foreach (Product product in products)
  {
    // 检查是否匹配上
    if ((product.ProductName.StartsWith(inputText)) ||
      (product.ProductCode.Contains(inputText)))
    {
      productMatches.Add(product.ProductName);
    }
  }
  // 返回匹配集合
  return productMatches.ToArray();
}

       当异步操作完成后,Silverlight应用中接收到返回的结果,然后我们将返回的建议输入列表作为ItemsSource属性的值。之后,我们还得调用PopulateComplete()方法用来告知AutoCompleteBox控件:新数据已经收到了。下面的示例展示了回调函数中是如何处理这项工作的:

private void GetProductMatchesCompleted(object sender,
  GetProductMatchesCompletedEventArgs e)
{
  // 检查是否web服务调用发生错误
  if (e.Error != null)
  {
    lblStatus.Text = e.Error.Message;
    return;
  }
  // 设置建议输入列表
  acbProducts.ItemsSource = e.Result;
  // 告知控件新数据已经收到了
  acbProducts.PopulateComplete();
}

       当使用一个耗时或者异步的操作来给控件填充建议输入列表的时候,有两个属性使我们可能需要调整的:MinimumPrefixLength和MinimumPopupDelay。其中,MinimumPrefixLength表示控件在给出建议输入下拉列表之前要输入的字符的长度。默认情况下,AutoCompleteBox控件在输入第1个字符后就会给出建议输入的下拉列表,如果我们想实现在输入3个字符后才开始进行建议输入列表的筛选(这是网上常见的基于Ajax技术的自动完成输入框的默认标准),那么就将MinimumPrefixLength属性设置为3即可。类似地,我们还可以通过MinimumPopupDelay属性来决定当用户停止键盘输入多长时间之后才开始进行建议输入的查询工作。这样就可以避免对一个缓慢的web服务的短时间多次调用导致的加载混乱和费时。当然,我们没有必要去判断建议输入列表的数据的获取需要多长时间——这是决定于初始化查询前的等待时间和连上web服务器之后到接受到返回响应的时间。

(说明:【文本控件 Text Controls】这一节内容太长了,拆开到下一篇继续)

转载于:https://www.cnblogs.com/xtechnet/archive/2012/09/24/Silverlight5_Chapter05_Part03.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值