软件、硬件定制开发,联系QQ:99605319
资源语言: 中文

搜索控件主要有三个部分:

       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"
                                                         ScrollViewer.HorizontalScrollBarVisibility="Auto"
                                                         MaxHeight="215"
                                                         VirtualizingStackPanel.IsVirtualizing="True"
                                                         BorderBrush="{DynamicResource Colorb9b9b9}"
                                                         BorderThickness="0">
                                                    <ListBox.ItemTemplate>
                                                        <DataTemplate>
                                                            <Label Content="{Binding Name}"/>
                                                        </DataTemplate>
                                                    </ListBox.ItemTemplate>
                                                    <ListBox.ItemContainerStyle>
                                                        <Style TargetType="{x:Type ListBoxItem}">
                                                            <Setter Property="Background"
                                                                    Value="Transparent" />
                                                            <Setter Property="Padding"
                                                                    Value="0" />
                                                            <Setter Property="BorderThickness"
                                                                    Value="0" />
                                                            <Setter Property="Template">
                                                                <Setter.Value>
                                                                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                                                        <Border x:Name="Bd"
                                                                                Height="38"
                                                                                Margin="0,0,0,4"
                                                                                BorderThickness="0"
                                                                                Background="{TemplateBinding Background}"
                                                                                SnapsToDevicePixels="true">
                                                                            <ContentPresenter HorizontalAlignment="Stretch"
                                                                                              Margin="14,0,0,0"
                                                                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                                                                        </Border>
                                                                        <ControlTemplate.Triggers>
 
                                                                            <Trigger Property="IsMouseOver"
                                                                                     Value="True">
                                                                                <Setter TargetName="Bd"
                                                                                        Property="BorderBrush"
                                                                                        Value="Chartreuse" />
                                                                                <Setter TargetName="Bd"
                                                                                        Property="Background"
                                                                                        Value="Chartreuse" />
                                                                                <Setter Property="Foreground"
                                                                                        Value="White" />
                                                                            </Trigger>
                                                                            <Trigger Property="IsSelected"
                                                                                     Value="true">
                                                                                <Setter Property="Background"
                                                                                        TargetName="Bd"
                                                                                        Value="Blue" />
                                                                                <Setter Property="Foreground"
                                                                                        Value="White" />
                                                                            </Trigger>
                                                                            <MultiTrigger>
                                                                                <MultiTrigger.Conditions>
                                                                                    <Condition Property="IsSelected"
                                                                                               Value="true" />
                                                                                    <Condition Property="Selector.IsSelectionActive"
                                                                                               Value="false" />
                                                                                </MultiTrigger.Conditions>
                                                                                <Setter Property="Background"
                                                                                        TargetName="Bd"
                                                                                        Value="{DynamicResource BgColorLeftTreeRowSelected}" />
                                                                                <Setter Property="Foreground"
                                                                                        Value="{DynamicResource ForegroundSelect}" />
                                                                            </MultiTrigger>
                                                                            <Trigger Property="IsEnabled"
                                                                                     Value="false">
                                                                                <Setter Property="Foreground"
                                                                                        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                                                                            </Trigger>
                                                                        </ControlTemplate.Triggers>
                                                                    </ControlTemplate>
                                                                </Setter.Value>
                                                            </Setter>
                                                        </Style>
                                                    </ListBox.ItemContainerStyle>
                                                </ListBox>
                                            </Grid>
                                        </Border>
                                    </Border>
 
                                </Border>
                            </Popup>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


       四 搜索模型
       搜索模型SearchModel用于将需要被搜索的原始数据构造成可用于控件搜索的数据。模型中的SearchField字段用于搜索匹配,Name用于搜索结果展示,Tag字段可用于存放原始数据。其中SearchField和Name为必需字段,ID和Tag可根据实际需要选择赋值。
    public class SearchModel
    {
        #region Fields
 
        private string _id = string.Empty;
        private string _name = string.Empty;
        private string _searchField = string.Empty;
        private object _tag = null;
 
        #endregion
 
        #region Properties
 
        public string Id { get => _id; set => _id = value; }
        public string Name { get => _name; set => _name = value; }
        public string SearchField { get => _searchField; set => _searchField = value; }
        public object Tag { get => _tag; set => _tag = value; }
 
        #endregion
    }


       五 逻辑控制
       以下代码为控件的逻辑控制代码。其中需要注意的要点有:

       1 当与模板中的TextBox的Text属性绑定的SearchText依赖属性的值发生改变时进行搜索。之所以不是监听TextBox的TextChanged事件进行搜索,是因为这样可以利用TextBox控件的延迟响应功能,避免短时间内向搜索框输入多个字符时没输入一个字符都会进行一次搜索。

       2 代码中提供了一个默认的搜索方法,只是简单的利用字符串的Contains方法进行匹配。同时可以为控件的SearchMethod委托赋值传入自定义的搜索方法。

       3 仍然监听TextBox的TextChanged事件是为了实时判断是否需要显示搜索提示语和清除按钮。

       4 搜索结果可以通过鼠标或者方向键来选中。

       5 当选中搜索结果中的一个项时,会触发SelectedSearchModelChanged事件

    public class SearchableTextBox : Control
    {
        #region Consts
 
        private const string SEARCH_ICON_STRING = "F1 M 14.8076,31.1139L 20.0677,25.9957C 19.3886,24.8199 19.25,23.4554 19.25,22C 19.25,17.5817 22.5817,14 27,14C 31.4183,14 35,17.5817 35,22C 35,26.4183 31.4183,29.75 27,29.75C 25.6193,29.75 24.3204,29.6502 23.1868,29.0345L 17.8861,34.1924C 17.105,34.9734 15.5887,34.9734 14.8076,34.1924C 14.0266,33.4113 14.0266,31.895 14.8076,31.1139 Z M 27,17C 24.2386,17 22,19.2386 22,22C 22,24.7614 24.2386,27 27,27C 29.7614,27 32,24.7614 32,22C 32,19.2386 29.7614,17 27,17 Z";
 
        #endregion
 
        #region Fields
 
        private TextBlock _ttbSearchTips = null;
        private TextBox _ttbInput = null;
        private Button _btnClear = null;
        private Popup _popup = null;
        private ListBox _lstSearchResult = null;
        private bool _canSearching = true;
 
        #endregion
 
        #region Propreties
 
        public Func<string, IList<SearchModel>, IList<SearchModel>> SearchMethod { get; set; }
 
        #endregion
 
        #region Dependency Properties
 
        /// <summary>
        /// 控件圆角半径
        /// </summary>
        public static readonly DependencyProperty CornerRadiusProperty
            = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(SearchableTextBox), new PropertyMetadata(new CornerRadius(0), null));
        /// <summary>
        /// 是否显示搜索图标
        /// </summary>
        public static readonly DependencyProperty IsShowSearchIconProperty
            = DependencyProperty.Register("IsShowSearchIcon", typeof(bool), typeof(SearchableTextBox), new PropertyMetadata(true, null));
        /// <summary>
        /// 搜索图标前景色
        /// </summary>
        public static readonly DependencyProperty SearchIconForegroundProperty
            = DependencyProperty.Register("SearchIconForeground", typeof(Brush), typeof(SearchableTextBox), new PropertyMetadata(new SolidColorBrush(Colors.Gray), null));
        /// <summary>
        /// 搜索图标
        /// </summary>
        public static readonly DependencyProperty SearchIconProperty
            = DependencyProperty.Register("SearchIcon", typeof(Geometry), typeof(SearchableTextBox), new PropertyMetadata(Geometry.Parse(SEARCH_ICON_STRING), null));
        /// <summary>
        /// 搜索图标高度
        /// </summary>
        public static readonly DependencyProperty SearchIconHeightProperty
            = DependencyProperty.Register("SearchIconHeight", typeof(double), typeof(SearchableTextBox), new PropertyMetadata(16.0, null));
        /// <summary>
        /// 搜索图标宽度
        /// </summary>
        public static readonly DependencyProperty SearchIconWidthProperty
            = DependencyProperty.Register("SearchIconWidth", typeof(double), typeof(SearchableTextBox), new PropertyMetadata(16.0, null));
        /// <summary>
        /// 是否显示搜索提示文字
        /// </summary>
        public static readonly DependencyProperty IsShowSearchTipsProperty
            = DependencyProperty.Register("IsShowSearchTips", typeof(bool), typeof(SearchableTextBox), new PropertyMetadata(true, null));
        /// <summary>
        /// 只是是否可以显示搜索框
        /// </summary>
        public static readonly DependencyProperty CanShowSearchTipsProperty
            = DependencyProperty.Register("CanShowSearchTips", typeof(bool), typeof(SearchableTextBox), new PropertyMetadata(true, null));
        /// <summary>
        /// 搜索提示文字
        /// </summary>
        public static readonly DependencyProperty SearchTipsProperty
            = DependencyProperty.Register("SearchTips", typeof(string), typeof(SearchableTextBox), new PropertyMetadata("请输入搜索条件", null));
        /// <summary>
        /// 搜索提示文字颜色
        /// </summary>
        public static readonly DependencyProperty SearchTipsForegroundProperty
            = DependencyProperty.Register("SearchTipsForeground", typeof(Brush), typeof(SearchableTextBox), new PropertyMetadata(new SolidColorBrush(Colors.Gray), null));
        /// <summary>
        /// 是否显示全部搜索结果
        /// </summary>
        public static readonly DependencyProperty IsShowAllSearchResultProperty
            = DependencyProperty.Register("IsShowAllSearchResult", typeof(bool), typeof(SearchableTextBox), new PropertyMetadata(true, null));
        /// <summary>
        /// (在不显示全部搜索结果的条件下)可显示的搜索结果的最大数据量
        /// </summary>
        public static readonly DependencyProperty MaxShownResultCountProperty
            = DependencyProperty.Register("MaxShownResultCount", typeof(int), typeof(SearchableTextBox), new PropertyMetadata(10, null));
        /// <summary>
        /// 传入的搜索源
        /// </summary>
        public static readonly DependencyProperty SearchItemsSourceProperty
            = DependencyProperty.Register("SearchItemsSource", typeof(IList<SearchModel>), typeof(SearchableTextBox), new PropertyMetadata(null, null));
        /// <summary>
        /// 搜索结果集合(用于绑定到ListBox)
        /// </summary>
        public static readonly DependencyProperty SearchResultCollectionProperty
            = DependencyProperty.Register("SearchResultCollection", typeof(ObservableCollection<SearchModel>), typeof(SearchableTextBox), new PropertyMetadata(new ObservableCollection<SearchModel>(), null));
        /// <summary>
        /// 是否允许显示清除按钮
        /// </summary>
        public static readonly DependencyProperty CanShowClearButtonProperty
            = DependencyProperty.Register("CanShowClearButton", typeof(bool), typeof(SearchableTextBox), new PropertyMetadata(true, OnCanShowClearButtonPropertyChanged));
        /// <summary>
        /// 输入的搜索条件字符串
        /// </summary>
        public static readonly DependencyProperty SearchTextProperty
            = DependencyProperty.Register("SearchText", typeof(string), typeof(SearchableTextBox), new PropertyMetadata("", OnSearchTextPropretyChanged));
        /// <summary>
        /// 选中的搜索结果项
        /// </summary>
        public static readonly DependencyProperty SelectedSearchItemProperty
            = DependencyProperty.Register("SelectedSearchItem", typeof(SearchModel), typeof(SearchableTextBox), new PropertyMetadata(null));
        #endregion
 
        #region Dependency Property Wrappers
 
        public CornerRadius CornerRadius
        {
            get { return (CornerRadius)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }
        public bool IsShowSearchIcon
        {
            get { return (bool)GetValue(IsShowSearchIconProperty); }
            set { SetValue(IsShowSearchIconProperty, value); }
        }
        public Brush SearchIconForeground
        {
            get { return (Brush)GetValue(SearchIconForegroundProperty); }
            set { SetValue(SearchIconForegroundProperty, value); }
        }
        public Geometry SearchIcon
        {
            get { return (Geometry)GetValue(SearchIconProperty); }
            set { SetValue(SearchIconProperty, value); }
        }
        public double SearchIconHeight
        {
            get { return (double)GetValue(SearchIconHeightProperty); }
            set { SetValue(SearchIconHeightProperty, value); }
        }
        public double SearchIconWidth
        {
            get { return (double)GetValue(SearchIconWidthProperty); }
            set { SetValue(SearchIconWidthProperty, value); }
        }
        public bool IsShowSearchTips
        {
            get { return (bool)GetValue(IsShowSearchTipsProperty); }
            set { SetValue(IsShowSearchTipsProperty, value); }
        }
        public bool CanShowSearchTips
        {
            get { return (bool)GetValue(CanShowSearchTipsProperty); }
            set { SetValue(CanShowSearchTipsProperty, value); }
        }
        public string SearchTips
        {
            get { return (string)GetValue(SearchTipsProperty); }
            set { SetValue(SearchTipsProperty, value); }
        }
        public Brush SearchTipsForeground
        {
            get { return (Brush)GetValue(SearchTipsForegroundProperty); }
            set { SetValue(SearchTipsForegroundProperty, value); }
        }
        public bool IsShowAllSearchResult
        {
            get { return (bool)GetValue(IsShowAllSearchResultProperty); }
            set { SetValue(IsShowAllSearchResultProperty, value); }
        }
        public int MaxShownResultCount
        {
            get { return (int)GetValue(MaxShownResultCountProperty); }
            set { SetValue(MaxShownResultCountProperty, value); }
        }
        public IList<SearchModel> SearchItemsSource
        {
            get { return (IList<SearchModel>)GetValue(SearchItemsSourceProperty); }
            set { SetValue(SearchItemsSourceProperty, value); }
        }
        public ObservableCollection<SearchModel> SearchResultCollection
        {
            get { return (ObservableCollection<SearchModel>)GetValue(SearchResultCollectionProperty); }
            set { SetValue(SearchResultCollectionProperty, value); }
        }
        public bool CanShowClearButton
        {
            get { return (bool)GetValue(CanShowClearButtonProperty); }
            set { SetValue(CanShowClearButtonProperty, value); }
        }
        public string SearchText
        {
            get { return (string)GetValue(SearchTextProperty); }
            set { SetValue(SearchTextProperty, value); }
        }
        public SearchModel SelectedSearchItem
        {
            get { return (SearchModel)GetValue(SelectedSearchItemProperty); }
            set { SetValue(SelectedSearchItemProperty, value); }
        }
        #endregion
 
        #region Routed Events
 
        /// <summary>
        /// 搜索结果选择改变事件
        /// </summary>
        public static readonly RoutedEvent SelectedSearchItemChangedEvent
            = EventManager.RegisterRoutedEvent("SelectedSearchItemChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SearchableTextBox));
 
        #endregion
 
        #region Event Wrappers
 
        public event RoutedEventHandler SelectedSearchItemChanged
        {
            add
            {
                base.AddHandler(SelectedSearchItemChangedEvent, value);
            }
            remove
            {
                base.RemoveHandler(SelectedSearchItemChangedEvent, value);
            }
        }
 
        #endregion
 
        #region Constructors
 
        static SearchableTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchableTextBox), new FrameworkPropertyMetadata(typeof(SearchableTextBox)));
        }
 
        #endregion
 
        #region Override Methods
 
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            PreviewKeyDown += SearchableTextBox_PreviewKeyDown;
 
            _ttbSearchTips = GetTemplateChild("PART_TextBlockTips") as TextBlock;
            _ttbInput = GetTemplateChild("PART_TextBoxInput") as TextBox;
            if (_ttbInput != null)
            {
                _ttbInput.TextChanged += _ttbInput_TextChanged;
            }
            _popup = GetTemplateChild("PART_Popup") as Popup;
            _lstSearchResult = GetTemplateChild("PART_ListBoxSearchResult") as ListBox;
            if (_lstSearchResult != null)
            {
                _lstSearchResult.PreviewMouseLeftButtonDown += _lstSearchResult_PreviewMouseLeftButtonDown;
            }
            _btnClear = GetTemplateChild("PART_ButtonClear") as Button;
            if (_btnClear != null)
            {
                _btnClear.Click += _btnClear_Click;
            }
        }
 
        #endregion
 
        #region Property Changed Callbacks
 
        /// <summary>
        /// 是否可显示清除按钮属性更改回调
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnCanShowClearButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SearchableTextBox stb = d as SearchableTextBox;
            if (stb == null || stb._btnClear == null)
            {
                return;
            }
 
            bool newValue = (bool)e.NewValue;
            if (!newValue)
            {
                stb._btnClear.Visibility = Visibility.Collapsed;
            }
            else if (stb._ttbInput != null && !string.IsNullOrEmpty(stb._ttbInput.Text))
            {
                stb._btnClear.Visibility = Visibility.Visible;
            }
        }
 
        /// <summary>
        /// 搜索条件更改回调
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnSearchTextPropretyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SearchableTextBox stb = d as SearchableTextBox;
            if (stb == null || !stb._canSearching)
            {
                return;
            }
 
            string searchKey = e.NewValue as string;
            if (string.IsNullOrEmpty(searchKey))//搜索关键字为空,不展示搜索popup
            {
                if (stb._popup != null)
                {
                    stb._popup.IsOpen = false;
                }
 
                return;
            }
 
            if (stb.SearchItemsSource == null || stb.SearchItemsSource.Count == 0)//搜索源为空,显示无搜索结果
            {
                if (stb._popup != null)
                {
                    stb._popup.IsOpen = true;
                }
 
                if (stb._lstSearchResult != null)
                {
                    stb._lstSearchResult.Visibility = Visibility.Collapsed;
                }
 
                return;
            }
 
            //根据关键字搜索匹配
            IList<SearchModel> searchResultList = null;
            if (stb.SearchMethod != null)
            {
                searchResultList = stb.SearchMethod(searchKey, stb.SearchItemsSource);
            }
            else
            {
                searchResultList = stb.DefaultSearch(searchKey, stb.SearchItemsSource);
            }
 
            lock (stb)
            {
                stb.SearchResultCollection.Clear();
                if (searchResultList != null && searchResultList.Count > 0)
                {
                    foreach (SearchModel sm in searchResultList)
                    {
                        stb.SearchResultCollection.Add(sm);
                    }
                }
 
                if (stb._popup != null)
                {
                    stb._popup.IsOpen = true;
                }
 
                if (stb._lstSearchResult != null)
                {
                    if (stb.SearchResultCollection.Count != 0)
                    {
                        stb._lstSearchResult.Visibility = Visibility.Visible;
 
                        //每次重新搜索,从头开始展示
                        VirtualizingPanel virtualizingPanel = stb._lstSearchResult.GetItemsHost() as VirtualizingPanel;
                        if (virtualizingPanel != null)
                        {
                            virtualizingPanel.CallEnsureGenerator();
                            virtualizingPanel.CallBringIndexIntoView(0);
                        }
 
                        ListBoxItem firstItem = (ListBoxItem)stb._lstSearchResult.ItemContainerGenerator.ContainerFromIndex(0);
                        if (null != firstItem)
                        {
                            firstItem.UpdateLayout();
                            firstItem.BringIntoView();
                        }
                    }
                    else
                    {
                        stb._lstSearchResult.Visibility = Visibility.Collapsed;
                    }
                }
            }
        }
 
        #endregion
 
        #region Event Methods
 
        private void _ttbInput_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (string.IsNullOrEmpty(_ttbInput.Text))//输入为空,显示Tips,隐藏清除按钮
            {
                if (CanShowSearchTips && _ttbSearchTips != null)
                {
                    _ttbSearchTips.Visibility = Visibility;
                }
 
                if (CanShowClearButton && _btnClear != null)
                {
                    //是Hidden而不是Collapsed,因为需要控件占位
                    _btnClear.Visibility = Visibility.Hidden;
                }
            }
            else//输入不为空,隐藏Tips,显示清除按钮(如果允许)
            {
                if (_ttbSearchTips != null)
                {
                    _ttbSearchTips.Visibility = Visibility.Collapsed;
                }
 
                if (CanShowClearButton && _btnClear != null)
                {
                    _btnClear.Visibility = Visibility.Visible;
                }
            }
        }
 
        private void _btnClear_Click(object sender, RoutedEventArgs e)
        {
            if (_ttbInput != null)
            {
                _ttbInput.Text = "";
            }
        }
 
        private void _lstSearchResult_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ListBoxItem item = LVTreeHelper.GetAncestor<ListBoxItem>((DependencyObject)e.OriginalSource);
            if (item == null)
            {
                return;
            }
 
            SetSelectedSearchItem(item.DataContext as SearchModel);
            _popup.IsOpen = false;
        }
 
        private void SearchableTextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (_popup == null || !_popup.IsOpen
                || _lstSearchResult == null || _lstSearchResult.Items.Count == 0)
            {
                return;
            }
 
            if (e.Key == Key.Down)
            {
                if (_lstSearchResult.SelectedIndex < _lstSearchResult.Items.Count - 1)
                {
                    _lstSearchResult.SelectedIndex = _lstSearchResult.SelectedIndex == -1 ? 0 : _lstSearchResult.SelectedIndex + 1;
                    _lstSearchResult.ScrollIntoView(_lstSearchResult.SelectedItem);
                }
            }
            if (e.Key == Key.Up)
            {
                if (_lstSearchResult.SelectedIndex == -1 || _lstSearchResult.SelectedIndex == 0)
                {
                    _lstSearchResult.SelectedIndex = 0;
                }
                else
                {
                    _lstSearchResult.SelectedIndex = _lstSearchResult.SelectedIndex - 1;
                    _lstSearchResult.ScrollIntoView(_lstSearchResult.SelectedItem);
                }
            }
            if (e.Key == Key.Enter)
            {
                SetSelectedSearchItem(_lstSearchResult.SelectedItem as SearchModel);
                _popup.IsOpen = false;
            }
 
            e.Handled = true;
        }
 
        #endregion
 
        #region Private Methods
 
        /// <summary>
        /// 默认搜索方法
        /// </summary>
        /// <param name="searchKey"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        private List<SearchModel> DefaultSearch(string searchKey, IList<SearchModel> source)
        {
            List<SearchModel> searchResultList = new List<SearchModel>();
            if (string.IsNullOrEmpty(searchKey) || source == null || source.Count == 0)
            {
                return searchResultList;
            }
 
            foreach (SearchModel sm in source)
            {
                if (sm.SearchField.Contains(searchKey))
                {
                    searchResultList.Add(sm);
                }
            }
 
            return searchResultList;
        }
 
        /// <summary>
        /// 设置选中的搜索结果项
        /// </summary>
        /// <param name="selectedItem"></param>
        private void SetSelectedSearchItem(SearchModel selectedSearchModel)
        {
            SelectedSearchItem = selectedSearchModel;
 
            RoutedEventArgs args = new RoutedEventArgs(SelectedSearchItemChangedEvent, this);
            RaiseEvent(args);
 
            if (selectedSearchModel == null)
            {
                return;
            }
 
            //更新搜索框显示内容为选中项
            _canSearching = false;
            SearchText = selectedSearchModel.Name;
            _canSearching = true;
        }
 
        #endregion
 
        #region Public Methods
 
        #endregion
    }


       六 控件的使用

       可通过绑定的方式指定搜索源数据

<UserControl x:Class="SearchableTextBoxExample.View.SearchableTextBoxExample"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SearchableTextBoxExample.View"
             xmlns:controls="clr-namespace:SearchableTextBox;assembly=SearchableTextBox"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
 
        <controls:SearchableTextBox x:Name="stbTest" Grid.Row="0" Width="200" Height="30"
                                   HorizontalAlignment="Center" VerticalAlignment="Center"
                                   BorderBrush="Red" BorderThickness="1" Background="Transparent" CornerRadius="12"
                                   IsShowSearchIcon="True"
                                   SearchItemsSource="{Binding SearchItemsSourceCollection}"
                                   SelectedSearchItemChanged="stbTest_SelectedSearchItemChanged"/>
 
        <StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Center">
            <TextBlock Text="搜索选中结果:" VerticalAlignment="Center"/>
            <TextBox  Text="{Binding SelectedSearchItem.Name, ElementName=stbTest}"
                      Width="100" IsEnabled="False" VerticalAlignment="Center"/>
        </StackPanel>
    </Grid>
</UserControl>



C#资源(WPF自定义搜索控件(net源码).7z)网址:https://www.08i8.com/ttkfzy/detail83347.html;转载请注明!


提示:
1、资源共享网(www.08i8.com)C#资源《WPF自定义搜索控件(net源码).7z》仅供研究学习请勿商用!
2、如果发现本资源违法或侵权请【报告管理员】
3、您所看到的所有资源都是网友分享,资源共享网(www.08i8.com)无法保证都能正常下载使用,
4、如果您发现资源无法下载或无法使用请【报告管理员】,管理员会联系资源发布者补充新资源!
5、如果暂时无法补充新资源,【只退积分!不退款!
6、关注微信公众号:《国资互联联盟》 不迷路!

与《WPF自定义搜索控件(net源码).7z》相关的《函数类库》



  • 窗口(对话框)模态闪动(Blink)、自定义窗口的四边拖拽支持、自定义窗口最大化(位置、大小)案例源码.rar

    窗口(对话框)模态闪动(Blink)、自定义窗口的四边拖拽支持、自定义窗口最大化(位置、大小)案例源码.rar

    WPF.UIShell UIFramework之自定义窗口的深度技术 - 模态闪动(Blink)、窗口四边拖拽支持(WmNCHitTest)、自定义最大化位置和大小(WmGetMinMaxInfo)的部分Code

    5 16899  0

  • 基于ComboBox 下拉多选 自定义控件 (C# 源码)

    基于ComboBox 下拉多选 自定义控件 (C# 源码)

    继承自C# Winform中ComboBox的下拉多选控件,操作简单,效果非常好1、多选。2、可绑定List,DataTable,Dictionary类型的数据源。3、在下拉列表中可显示自定义的多列数据。4、可在下拉列表中通过输入关键字,自动搜索符合条件的数据行。5、可指定不同的值列和显示列。6、可设置是否显示行头和列头。7、程序根据显示列的多少和宽度,自动调整下拉界面的宽度。

    5 9789  0


  • WPF结合MVVM绑定Datagrid

    WPF结合MVVM绑定Datagrid

    用vs2019打开最好。里面实现了增加、删除、修改、以及单击之后显示数据。

    5 77194  0

  • zgwxw
    zgwxw Rank: 16

    0

    0

    0

    ( 此人很懒并没有留下什么~~ )
    img

    WPF自定义搜索控件(net源码).7z

    下载积分 钻石会员
    5 免费
    请您 登录后 下载 !
    说明

    您下载所消耗的积分将转交上传作者。上传资源,免费获取积分!


    首页

    栏目

    搜索

    会员