我有一个WPF Listbox控件,我想允许用户使用预先输入更改所选项目。我正在寻找的行为与Windows资源管理器完全一样。当您继续键入文件夹名称的文本时,列表将继续选择更正确的项目。
例如假设这个文件夹结构:
OtherFolderName
MyFirstFolder
MyFirstFileFolder
MyFirstList
如果您使用鼠标选择OtherFolderName
,则开始输入MyFirstF
将选择项MyFirstFolder
,但如果您继续键入MyFirstFi
项MyFirstFileFolder
将被选中。
我的WPF列表框没有表现出这种行为,我希望我可以轻松启用它,因为旧的WinForms列表框就是这样做的。
答案 0 :(得分:7)
查看TextSearch类,特别是TextSearch.TextPath附加属性:
<ListBox TextSearch.TextPath="FolderName" ... />
TextSearch.TextPath属性启用文本搜索,并指定如何从每个项目中提取搜索文本。在这种情况下,我假设每个Folder对象都有一个名为“FolderName”的属性。
如果这不能满足您的所有需求,您可能必须实施自己的搜索,因为TextSearch功能不是特别可调。要做到这一点:
我会使用附加属性将其构建为一个单独的类,类似于内置的TextSearch类。
答案 1 :(得分:0)
我使用一个隐藏的TextBox,在人输入时会短暂显示,并在几秒后重置并清除,以便在计时器到期后不会尝试匹配其内容。此人将键入ListBox,并且由于KeyUp
上的绑定,其SearchText
事件将填充TextBox。填充SearchText
时,会触发MyFilteredItems()
以执行该文本与ListBox之间的匹配。然后,如果此人按Enter键,则选择将进入另一个TextBox(未在XAML中列出,但在代码中注释掉)并从lstPickList
中清除。然后清除TextBox并重置计时器。
XAML:
<TextBox Name="txtPicker" IsReadOnly="True" Foreground="LightGreen" FontFamily="Consolas" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<ListBox Name="lstPickList" Grid.Row="1" ItemsSource="{Binding MyFilteredItems}" KeyUp="lstPickList_KeyUp"></ListBox>
然后这是相关的代码隐藏:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private Timer t = new Timer();
public System.Windows.Threading.DispatcherTimer tCleanup =
new System.Windows.Threading.DispatcherTimer();
private string _searchText;
public string SearchText
{
get { return _searchText; }
set
{
_searchText = value;
OnPropertyChanged("SearchText");
OnPropertyChanged("MyFilteredItems");
}
}
public List<string> MyItems { get; set; }
public IEnumerable<string> MyFilteredItems
{
get
{
if (SearchText == null) return MyItems;
return MyItems.Where(x => x.ToUpper().StartsWith(SearchText.ToUpper()));
}
}
public MainWindow()
{
InitializeComponent();
MyItems = new List<string>() { "ABC", "DEF", "GHI" };
this.DataContext = this;
t.Interval = 1000;
t.Elapsed += new ElapsedEventHandler(timerCounter);
tCleanup.Interval = new TimeSpan(0,0,1);
tCleanup.Tick += new EventHandler(cleanupCounter_Tick);
txtPicker.Visibility = Visibility.Collapsed;
tCleanup.Start();
}
private static int counter = 0;
protected void timerCounter(object sender, ElaspedEventArgs e)
{
counter++;
}
protected void cleanupCounter_Tick(object sender, EventArgs e)
{
if (counter > 2 && txtPicker.Visibility == Visibility.Visible)
txtPicker.Visibility = Visibility.Collapsed;
}
private void lstPickList_KeyUp(object sender, KeyEventArgs e)
{
ListBox lst = (ListBox)sender;
string strg = Convert.ToString(e.Key.ToString().Replace("D",""));
if (counter < 2)
{
txtPicker.Visibility = Visibility.Visible;
t.Start();
if (strg == "Return")
{
txtPicker.Text += "{Enter}";
SearchText += "{Enter}";
}
else
{
txtPicker.Text += strg;
SearchText += strg;
}
}
else
{
SearchText = strg;
txtPicker.Text = strg;
t.Stop();
counter = 0;
t.Start();
}
if (strg == "Return")
{
// This next line would be if you had a "selected items" ListBox to store the item
// lstSelectedList.Items.Add(lstPickList.SelectedItem);
lstPickList.Items.Remove(lstPickList.SelectedItem);
t.Stop();
txtPicker.Visibility = Visibility.Collapsed;
counter = 0;
txtPicker.Text = String.Empty;
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string name)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}