原文链接:http://blog.csdn.net/zhuo_wp/article/details/78821711 转载请注明出处
在利用WPF开发桌面软件时,我们常常会用到自动搜索功能:在一个搜索框中输入搜索关键字,得到搜索结果,并可以选择某一项搜索结果。WPF中没有这样的预定义控件,不过这一搜索功能可以简单的利用TextBox来实现,我们只需要监听TextBox的TextChanged事件,在事件处理方法中查找搜索源中与输入关键字匹配的项。但是,如果这样的搜索场景被大量使用的时候,最好的处理方式是封装一个可专门用于搜索功能的自定义控件。本文即是简要的说明其思路与简单实现的。
一 设计思路
如图所示,从界面上说,搜索控件主要有三个部分:
1 搜索关键字输入部分,主要用于搜索关键字的输入,可以用WPF中的TextBox来实现,需要监听TextBox的TextChanged事件。
2 清除搜索关键字按钮,用于一键清除输入框中的关键字,可用Button来实现。
3 搜索结果展示部分,用于展示搜索结果,并且只有在有搜索结果的时候才展示,可以用WPF中的Popup来实现。
此外,还可以显示搜索提示语和搜索图标。
在应用控件的时候,搜索数据源是可以从控件外部提供的,所以需要依赖属性来绑定搜索源,同时搜索提示语可以通过依赖属性来提供自定义设置功能。
二 代码结构
如图所示,整个控件的代码结构包括用于界面构建的SearchableTextBox.xaml文件,用于搜索逻辑控制的SearchableTextBox.cs文件,用于将原始数据构造成可搜索数据的SearchModel类,以及一些辅助方法类。
三 模板代码
如下所示,搜索控件的默认模板包括:
1 一个Path元素,用于显示搜索图标。
2 一个TextBlock控件,用于显示搜索提示语。
3 一个TextBox控件, 用于数据搜索关键字。
4 一个Button控件,用于一键清除输入框中的内容。
5 一个Popup和一个ListBox,用于显示搜索结果。
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SearchableTextBox"
xmlns:cvt="clr-namespace:SearchableTextBox.Converters">
<cvt:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<cvt:CornerRadiusToDoubleConverter x:Key="CornerRadiusToDoubleConverter"/>
<Style TargetType="{x:Type local:SearchableTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SearchableTextBox}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<Grid x:Name="PART_Root">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Width="{TemplateBinding CornerRadius, Converter={StaticResource CornerRadiusToDoubleConverter}}"/>
<Path Grid.Column="1" Width="{TemplateBinding SearchIconWidth}"
Height="{TemplateBinding SearchIconHeight}"
Visibility="{TemplateBinding IsShowSearchIcon, Converter={StaticResource BoolToVisibilityConverter}}"
Stretch="Fill" Fill="{TemplateBinding SearchIconForeground}"
Data="{TemplateBinding SearchIcon}">
</Path>
<TextBlock x:Name="PART_TextBlockTips" Grid.Column="2" Text="{TemplateBinding SearchTips}" Margin="15,0,0,0"
Foreground="{TemplateBinding SearchTipsForeground}"
HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBox x:Name="PART_TextBoxInput" Grid.Column="2"
Text="{Binding SearchText,Delay=500, Mode=TwoWay,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:SearchableTextBox}, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="Transparent" BorderThickness="0" Background="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center"/>
<Button x:Name="PART_ButtonClear" Grid.Column="3" Visibility="Collapsed">
<Button.Template>
<ControlTemplate>
<Grid>
<Label Content="x"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
<Grid Grid.Column="4" Width="{TemplateBinding CornerRadius, Converter={StaticResource CornerRadiusToDoubleConverter}}"/>
<Popup x:Name="PART_Popup"
AllowsTransparency="true"
PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
Placement="Bottom"
StaysOpen="False">
<Border Padding="0,0,4,0">
<Border x:Name="Shdw"
Background="Transparent"
MaxWidth="252"
MinWidth="{Binding ActualWidth, ElementName=PART_Root}">
<Border x:Name="DropDownBorder"
Margin="0,4,0,0"
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}"
BorderThickness="1"
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<Grid RenderOptions.ClearTypeHint="Enabled">
<Border Padding="14"
Background="White"
Name="NoResultBorder">
<TextBlock Text="无匹配结果"
Foreground="Black" />
</Border>
<ListBox x:Name="PART_ListBoxSearchResult"
ItemsSource="{TemplateBinding SearchResultCollection}"
Foreground="Black"
Margin="0,10"
Padding="0"
Background="White"