WPF 之 实现TextBox输入文字后自动弹出数据(类似百度的输入框)

1、添加一个数据实体类 AutoCompleteEntry,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCClient.AppCode
{
    public class AutoCompleteEntry
    {
        private string[] keywordStrings;
        private string displayString;

        public string[] KeywordStrings
        {
            get
            {
                if (keywordStrings == null)
                {
                    keywordStrings = new string[] { displayString };
                }
                return keywordStrings;
            }
        }

        public string DisplayName
        {
            get { return displayString; }
            set { displayString = value; }
        }

        public AutoCompleteEntry(string name, params string[] keywords)
        {
            displayString = name;
            keywordStrings = keywords;
        }

        public override string ToString()
        {
            return displayString;
        }
    }
}

2、创建一个继承至Canvas的控件,并命名为AutoCompleteTextBox,前台 AutoCompleteTextBox.xam l代码,如下:

<Canvas x:Class="FCClient.CustomControls.AutoCompleteTextBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="30" Width="300">
</Canvas>

3、后台 AutoCompleteTextBox 代码,如下:

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Timers;

using FCClient.AppCode;

namespace FCClient.CustomControls
{
    /// <summary>
    /// 自定义自动匹配文本框
    /// </summary>    
    public partial class AutoCompleteTextBox : Canvas
    {
        #region 成员变量

        private VisualCollection controls;
        private TextBox textBox;
        private ComboBox comboBox;
        private ObservableCollection<AutoCompleteEntry> autoCompletionList;
        private Timer keypressTimer;
        private delegate void TextChangedCallback();
        private bool insertText;
        private int delayTime;
        private int searchThreshold;

        #endregion 成员变量

        #region 构造函数

        public AutoCompleteTextBox()
        {
            controls = new VisualCollection(this);
            InitializeComponent();

            autoCompletionList = new ObservableCollection<AutoCompleteEntry>();
            searchThreshold = 0;        // default threshold to 2 char
            delayTime = 100;

            // set up the key press timer
            keypressTimer = new System.Timers.Timer();
            keypressTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);

            // set up the text box and the combo box
            comboBox = new ComboBox();
            comboBox.IsSynchronizedWithCurrentItem = true;
            comboBox.IsTabStop = false;
            Panel.SetZIndex(comboBox, -1);
            comboBox.SelectionChanged += new SelectionChangedEventHandler(comboBox_SelectionChanged);

            textBox = new TextBox();
            textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged);
            textBox.GotFocus += new RoutedEventHandler(textBox_GotFocus);
            textBox.KeyUp += new KeyEventHandler(textBox_KeyUp);
            textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
            textBox.VerticalContentAlignment = VerticalAlignment.Center;

            controls.Add(comboBox);
            controls.Add(textBox);
        }

        #endregion 构造函数

        #region 成员方法

        public string Text
        {
            get { return textBox.Text; }
            set
            {
                insertText = true;
                textBox.Text = value;
            }
        }

        public int DelayTime
        {
            get { return delayTime; }
            set { delayTime = value; }
        }

        public int Threshold
        {
            get { return searchThreshold; }
            set { searchThreshold = value; }
        }

        /// <summary>
        /// 添加Item
        /// </summary>
        /// <param name="entry"></param>
        public void AddItem(AutoCompleteEntry entry)
        {
            autoCompletionList.Add(entry);
        }

        /// <summary>
        /// 清空Item
        /// </summary>
        /// <param name="entry"></param>
        public void ClearItem()
        {
            autoCompletionList.Clear();
        }

        private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (null != comboBox.SelectedItem)
            {
                insertText = true;
                ComboBoxItem cbItem = (ComboBoxItem)comboBox.SelectedItem;
                textBox.Text = cbItem.Content.ToString();
            }
        }

        private void TextChanged()
        {
            try
            {
                comboBox.Items.Clear();
                if (textBox.Text.Length >= searchThreshold)
                {
                    foreach (AutoCompleteEntry entry in autoCompletionList)
                    {
                        foreach (string word in entry.KeywordStrings)
                        {
                            if (word.Contains(textBox.Text))
                            {
                                ComboBoxItem cbItem = new ComboBoxItem();
                                cbItem.Content = entry.ToString();
                                comboBox.Items.Add(cbItem);
                                break;
                            }
                            //if (word.StartsWith(textBox.Text, StringComparison.CurrentCultureIgnoreCase))
                            //{
                            //    ComboBoxItem cbItem = new ComboBoxItem();
                            //    cbItem.Content = entry.ToString();
                            //    comboBox.Items.Add(cbItem);
                            //    break;
                            //}
                        }
                    }
                    comboBox.IsDropDownOpen = comboBox.HasItems;
                }
                else
                {
                    comboBox.IsDropDownOpen = false;
                }
            }
            catch { }
        }

        private void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
        {
            keypressTimer.Stop();
            Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
                new TextChangedCallback(this.TextChanged));
        }

        private void textBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // text was not typed, do nothing and consume the flag
            if (insertText == true) insertText = false;

            // if the delay time is set, delay handling of text changed
            else
            {
                if (delayTime > 0)
                {
                    keypressTimer.Interval = delayTime;
                    keypressTimer.Start();
                }
                else TextChanged();
            }
        }

        //获得焦点时
        public void textBox_GotFocus(object sender, RoutedEventArgs e)
        {
            // text was not typed, do nothing and consume the flag
            if (insertText == true) insertText = false;

            // if the delay time is set, delay handling of text changed
            else
            {
                if (delayTime > 0)
                {
                    keypressTimer.Interval = delayTime;
                    keypressTimer.Start();
                }
                else TextChanged();
            }
        }

        public void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (textBox.IsInputMethodEnabled == true)
            {
                comboBox.IsDropDownOpen = false;
            }
        }

        /// <summary>
        /// 按向下按键时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void textBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Down && comboBox.IsDropDownOpen == true)
            {
                comboBox.Focus();
            }
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            textBox.Arrange(new Rect(arrangeSize));
            comboBox.Arrange(new Rect(arrangeSize));
            return base.ArrangeOverride(arrangeSize);
        }

        protected override Visual GetVisualChild(int index)
        {
            return controls[index];
        }

        protected override int VisualChildrenCount
        {
            get { return controls.Count; }
        }

        #endregion 成员方法
    }
}

4.、使用创建的 AutoCompleteTextbox ,新建一个WPF工程,在Windows1.xaml 中添加自定义的控件,如下:

<Window x:Class="WPFAutoCompleteTextbox.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFAutoCompleteTextbox"        
    Title="WPF AutoCompleteTextBox" Height="195" Width="561">
    <Grid Background="SteelBlue">
        <Button Name="button1" Height="23" Width="75" Margin="12,12,0,0" Click="button1_Click" 
         HorizontalAlignment
="Left" VerticalAlignment="Top">Clear</Button> <local:AutoCompleteTextBox Height="23" Width="162" x:Name="textBox1" Margin="25,65,0,0"
          HorizontalAlignment
="Left" VerticalAlignment="Top" /> </Grid> </Window>

5、 在 Windows1.cs 中初始化搜索数据,如下:

    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            textBox1.AddItem(new AutoCompleteEntry("上海", null));
            textBox1.AddItem(new AutoCompleteEntry("北京", null));
            textBox1.AddItem(new AutoCompleteEntry("济南", null));
            textBox1.AddItem(new AutoCompleteEntry("青岛", null));
            textBox1.AddItem(new AutoCompleteEntry("天津", null));
            textBox1.AddItem(new AutoCompleteEntry("黑龙江", null));
            textBox1.AddItem(new AutoCompleteEntry("聊城", null));
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            textBox1.Text = string.Empty;
        }
    }
原文地址:https://www.cnblogs.com/xinaixia/p/5549843.html