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