1. 创建一个继承至Canvas的控件,并命名为WPFAutoCompleteTextbox
2. 在WPFAutoCompleteTextbox.cs中增加以下代码
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WPFAutoCompleteTextbox { /// <summary> /// Interaction logic for AutoCompleteTextBox.xaml /// </summary> public partial class AutoCompleteTextBox : Canvas { #region Members private VisualCollection controls; private TextBox textBox; private ComboBox comboBox; private ObservableCollection<AutoCompleteEntry> autoCompletionList; private System.Timers.Timer keypressTimer; private delegate void TextChangedCallback(); private bool insertText; private int delayTime; private int searchThreshold; #endregion #region Constructor public AutoCompleteTextBox() { controls = new VisualCollection(this); InitializeComponent(); autoCompletionList = new ObservableCollection<AutoCompleteEntry>(); searchThreshold = 2; // default threshold to 2 char // 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; comboBox.SelectionChanged += new SelectionChangedEventHandler(comboBox_SelectionChanged); textBox = new TextBox(); textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged); textBox.VerticalContentAlignment = VerticalAlignment.Center; controls.Add(comboBox); controls.Add(textBox); } #endregion #region Methods 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; } } public void AddItem(AutoCompleteEntry entry) { autoCompletionList.Add(entry); } 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.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(); } } 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 } }
<Canvas x:Class="WPFAutoCompleteTextbox.AutoCompleteTextBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </Canvas>
<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="200" Width="300"> <StackPanel Background="SteelBlue"> <Button Name="button1" Height="23" Width="75" Margin="20" Click="button1_Click" HorizontalAlignment="Left">Clear</Button> <local:AutoCompleteTextBox Height="23" Width="240" x:Name="textBox1" DelayTime="500" Threshold="2"/> </StackPanel> </Window>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WPFAutoCompleteTextbox { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); textBox1.AddItem(new AutoCompleteEntry("Toyota Camry", "Toyota Camry", "camry", "car", "sedan")); textBox1.AddItem(new AutoCompleteEntry("Toyota Corolla", "Toyota Corolla", "corolla", "car", "compact")); textBox1.AddItem(new AutoCompleteEntry("Toyota Tundra", "Toyota Tundra", "tundra", "truck")); textBox1.AddItem(new AutoCompleteEntry("Chevy Impala", null)); // null matching string will default with just the name textBox1.AddItem(new AutoCompleteEntry("Chevy Tahoe", "Chevy Tahoe", "tahoe", "truck", "SUV")); textBox1.AddItem(new AutoCompleteEntry("Chevrolet Malibu", "Chevrolet Malibu", "malibu", "car", "sedan")); } private void button1_Click(object sender, RoutedEventArgs e) { textBox1.Text = string.Empty; } } }