最近在一个WPF项目中用到一个下拉列表,随着用户输入字符而进行显示,使用了绑定等知识,虽然实现比较简单,可是在性能上也是想了很多办法终于才勉强可以用,与大家分享下。
用于页面绑定的模型类:
- public class MainWindowModel : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
- private ObservableCollection<Content> names = new ObservableCollection<Content>();
- private bool popupIsOpen = false;
- public bool PopupIsOpen
- {
- get
- {
- return popupIsOpen;
- }
- set
- {
- popupIsOpen = value;
- this.PropertyChanged(this, new PropertyChangedEventArgs("PopupIsOpen"));
- }
- }
- public ObservableCollection<Content> Names
- {
- get
- {
- return this.names;
- }
- set
- {
- this.names = value;
- this.PropertyChanged(this, new PropertyChangedEventArgs("Names"));
- }
- }
- }
- public class Content
- {
- private string name=string.Empty;
- public string Name
- {
- get
- {
- return this.name;
- }
- set
- {
- name = value;
- }
- }
- }
public class MainWindowModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Content> names = new ObservableCollection<Content>();
private bool popupIsOpen = false;
public bool PopupIsOpen
{
get
{
return popupIsOpen;
}
set
{
popupIsOpen = value;
this.PropertyChanged(this, new PropertyChangedEventArgs("PopupIsOpen"));
}
}
public ObservableCollection<Content> Names
{
get
{
return this.names;
}
set
{
this.names = value;
this.PropertyChanged(this, new PropertyChangedEventArgs("Names"));
}
}
}
public class Content
{
private string name=string.Empty;
public string Name
{
get
{
return this.name;
}
set
{
name = value;
}
}
}
后台代码:
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window
- {
- private MainWindowModel model = new MainWindowModel();
- private List<BackgroundWorker> threadPool = new List<BackgroundWorker>();
- public MainWindow()
- {
- InitializeComponent();
- this.DataContext = model;
- }
- /// <summary>
- /// 在此增加内容
- /// </summary>
- private void InitialSetValue()
- {
- this.Dispatcher.BeginInvoke(new Action(() =>
- {
- this.model.Names.Clear();
- for (int i = 0; i < 100; i++)
- {
- Content content = new Content();
- content.Name = i.ToString() + i.ToString() +
- i.ToString() + i.ToString() + i.ToString();
- this.model.Names.Add(content);
- }
- }));
- }
- /// <summary>
- /// 下拉菜单消失要清空内容
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void popupContent_Closed(object sender, EventArgs e)
- {
- this.model.Names.Clear();
- }
- /// <summary>
- /// 文本框失去焦点,下拉列表隐藏
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void textBox1_LostFocus(object sender, RoutedEventArgs e)
- {
- this.model.PopupIsOpen = false;
- }
- /// <summary>
- /// 文字内容改变,下拉类表出现
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
- {
- this.model.PopupIsOpen = true;
- if (threadPool.Count > 0)
- {
- threadPool[0].CancelAsync();
- }
- threadPool.Clear();
- string key = this.textBox1.Text.Trim();
- if (string.IsNullOrEmpty(key))
- {
- this.model.PopupIsOpen = false;
- return;
- }
- BackgroundWorker worker = new BackgroundWorker();
- worker.WorkerReportsProgress = true;
- worker.WorkerSupportsCancellation = true;
- worker.DoWork += (o, p) =>
- {
- InitialSetValue();
- p.Result = this.model.Names;
- };
- worker.RunWorkerCompleted += (o, p) =>
- {
- this.model.Names = p.Result as ObservableCollection<Content>;
- if (this.model.Names.Count <= 0)
- {
- this.model.PopupIsOpen = false;
- }
- };
- threadPool.Add(worker);
- Thread.Sleep(100);
- if (threadPool.Count > 0)
- {
- threadPool[0].RunWorkerAsync();
- }
- }
- /// <summary>
- /// 子项被选中,下拉列表消失
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void item_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- var data = (sender as ListBox).SelectedItem as Content;
- if (data == null)
- {
- this.model.PopupIsOpen = false;
- return;
- }
- try
- {
- this.textBox1.TextChanged -= new TextChangedEventHandler(textBox1_TextChanged);
- var searchtext = data.Name;
- this.model.PopupIsOpen = false;
- }
- catch
- {
- }
- finally
- {
- this.textBox1.TextChanged += new TextChangedEventHandler(textBox1_TextChanged);
- }
- }
- }
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private MainWindowModel model = new MainWindowModel();
private List<BackgroundWorker> threadPool = new List<BackgroundWorker>();
public MainWindow()
{
InitializeComponent();
this.DataContext = model;
}
/// <summary>
/// 在此增加内容
/// </summary>
private void InitialSetValue()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.model.Names.Clear();
for (int i = 0; i < 100; i++)
{
Content content = new Content();
content.Name = i.ToString() + i.ToString() +
i.ToString() + i.ToString() + i.ToString();
this.model.Names.Add(content);
}
}));
}
/// <summary>
/// 下拉菜单消失要清空内容
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void popupContent_Closed(object sender, EventArgs e)
{
this.model.Names.Clear();
}
/// <summary>
/// 文本框失去焦点,下拉列表隐藏
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textBox1_LostFocus(object sender, RoutedEventArgs e)
{
this.model.PopupIsOpen = false;
}
/// <summary>
/// 文字内容改变,下拉类表出现
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
this.model.PopupIsOpen = true;
if (threadPool.Count > 0)
{
threadPool[0].CancelAsync();
}
threadPool.Clear();
string key = this.textBox1.Text.Trim();
if (string.IsNullOrEmpty(key))
{
this.model.PopupIsOpen = false;
return;
}
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += (o, p) =>
{
InitialSetValue();
p.Result = this.model.Names;
};
worker.RunWorkerCompleted += (o, p) =>
{
this.model.Names = p.Result as ObservableCollection<Content>;
if (this.model.Names.Count <= 0)
{
this.model.PopupIsOpen = false;
}
};
threadPool.Add(worker);
Thread.Sleep(100);
if (threadPool.Count > 0)
{
threadPool[0].RunWorkerAsync();
}
}
/// <summary>
/// 子项被选中,下拉列表消失
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void item_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var data = (sender as ListBox).SelectedItem as Content;
if (data == null)
{
this.model.PopupIsOpen = false;
return;
}
try
{
this.textBox1.TextChanged -= new TextChangedEventHandler(textBox1_TextChanged);
var searchtext = data.Name;
this.model.PopupIsOpen = false;
}
catch
{
}
finally
{
this.textBox1.TextChanged += new TextChangedEventHandler(textBox1_TextChanged);
}
}
}
页面代码:
- <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>
- lt;/Window>
<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