最近在一個WPF項目中用到一個下拉列表,隨着用戶輸入字符而進行顯示,使用了綁定等知識,雖然實現比較簡單,可是在性能上也是想了很多辦法終於才勉強可以用,與大家分享下。
用於頁面綁定的模型類:
1 public class MainWindowModel : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 5 private ObservableCollection<Content> names = new ObservableCollection<Content>(); 6 7 private bool popupIsOpen = false; 8 9 public bool PopupIsOpen 10 { 11 get 12 { 13 return popupIsOpen; 14 } 15 16 set 17 { 18 popupIsOpen = value; 19 20 this.PropertyChanged(this, new PropertyChangedEventArgs("PopupIsOpen")); 21 } 22 } 23 24 public ObservableCollection<Content> Names 25 { 26 get 27 { 28 return this.names; 29 } 30 31 set 32 { 33 this.names = value; 34 35 this.PropertyChanged(this, new PropertyChangedEventArgs("Names")); 36 } 37 } 38 } 39 40 public class Content 41 { 42 private string name=string.Empty; 43 44 public string Name 45 { 46 get 47 { 48 return this.name; 49 } 50 51 set 52 { 53 name = value; 54 } 55 } 56 }
后台代碼:
1 /// <summary> 2 /// MainWindow.xaml 的交互邏輯 3 /// </summary> 4 public partial class MainWindow : Window 5 { 6 private MainWindowModel model = new MainWindowModel(); 7 8 private List<BackgroundWorker> threadPool = new List<BackgroundWorker>(); 9 10 public MainWindow() 11 { 12 InitializeComponent(); 13 14 this.DataContext = model; 15 } 16 17 /// <summary> 18 /// 在此增加內容 19 /// </summary> 20 private void InitialSetValue() 21 { 22 this.Dispatcher.BeginInvoke(new Action(() => 23 { 24 this.model.Names.Clear(); 25 26 for (int i = 0; i < 100; i++) 27 { 28 Content content = new Content(); 29 30 content.Name = i.ToString() + i.ToString() + 31 i.ToString() + i.ToString() + i.ToString(); 32 33 this.model.Names.Add(content); 34 } 35 })); 36 } 37 38 /// <summary> 39 /// 下拉菜單消失要清空內容 40 /// </summary> 41 /// <param name="sender"></param> 42 /// <param name="e"></param> 43 private void popupContent_Closed(object sender, EventArgs e) 44 { 45 this.model.Names.Clear(); 46 } 47 48 /// <summary> 49 /// 文本框失去焦點,下拉列表隱藏 50 /// </summary> 51 /// <param name="sender"></param> 52 /// <param name="e"></param> 53 private void textBox1_LostFocus(object sender, RoutedEventArgs e) 54 { 55 this.model.PopupIsOpen = false; 56 } 57 58 /// <summary> 59 /// 文字內容改變,下拉類表出現 60 /// </summary> 61 /// <param name="sender"></param> 62 /// <param name="e"></param> 63 private void textBox1_TextChanged(object sender, TextChangedEventArgs e) 64 { 65 this.model.PopupIsOpen = true; 66 67 if (threadPool.Count > 0) 68 { 69 threadPool[0].CancelAsync(); 70 } 71 72 threadPool.Clear(); 73 74 string key = this.textBox1.Text.Trim(); 75 76 if (string.IsNullOrEmpty(key)) 77 { 78 this.model.PopupIsOpen = false; 79 80 return; 81 } 82 83 BackgroundWorker worker = new BackgroundWorker(); 84 85 worker.WorkerReportsProgress = true; 86 87 worker.WorkerSupportsCancellation = true; 88 89 worker.DoWork += (o, p) => 90 { 91 InitialSetValue(); 92 93 p.Result = this.model.Names; 94 }; 95 96 worker.RunWorkerCompleted += (o, p) => 97 { 98 this.model.Names = p.Result as ObservableCollection<Content>; 99 100 if (this.model.Names.Count <= 0) 101 { 102 this.model.PopupIsOpen = false; 103 } 104 }; 105 106 threadPool.Add(worker); 107 108 Thread.Sleep(100); 109 110 if (threadPool.Count > 0) 111 { 112 threadPool[0].RunWorkerAsync(); 113 } 114 } 115 116 /// <summary> 117 /// 子項被選中,下拉列表消失 118 /// </summary> 119 /// <param name="sender"></param> 120 /// <param name="e"></param> 121 private void item_SelectionChanged(object sender, SelectionChangedEventArgs e) 122 { 123 var data = (sender as ListBox).SelectedItem as Content; 124 125 if (data == null) 126 { 127 this.model.PopupIsOpen = false; 128 129 return; 130 } 131 132 try 133 { 134 this.textBox1.TextChanged -= new TextChangedEventHandler(textBox1_TextChanged); 135 136 var searchtext = data.Name; 137 138 this.model.PopupIsOpen = false; 139 } 140 catch 141 { 142 } 143 finally 144 { 145 this.textBox1.TextChanged += new TextChangedEventHandler(textBox1_TextChanged); 146 } 147 } 148 }
頁面代碼:
<Window x:Class="TestPopup.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <TextBox Height="38" HorizontalAlignment="Left" Margin="71,89,0,0" LostFocus="textBox1_LostFocus" TextChanged="textBox1_TextChanged" Name="textBox1" VerticalAlignment="Top" Width="236" /> <Popup Name="popupContent" StaysOpen="False" IsOpen="{Binding PopupIsOpen}" Closed="popupContent_Closed" Placement="Bottom" PlacementTarget="{Binding ElementName=textBox1}" > <ListBox Name="contentItems" SelectionChanged="item_SelectionChanged" ItemsSource="{Binding Names}" MinWidth="{Binding ElementName=textBox1, Path=ActualWidth}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Margin="5,5" FontSize="15" Text="{Binding Name}" Foreground="Gray"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Popup> </Grid> </Window>
效果:
主要注意的有一點,下拉列表消失時一定要清除數據,不然下次顯示的時候會很慢。在用的時候找了好久才發現這個問題。 詳細工程:http://download.csdn.net/detail/yysyangyangyangshan/4762184