我有一个包含客户信息的列表视图。列表视图上方有一个搜索文本框。当您在文本框中键入任何内容时,它会高亮显示列表视图中的匹配项。但是,问题在于它仅在列表视图的可视化侧进行搜索。它不会在列表视图的未滚动侧(列表视图的底部)中搜索。我的代码如下。请看一看。
private void FindListViewItem(DependencyObject obj)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
ListViewItem lv = obj as ListViewItem;
if (lv != null)
{
HighlightText(lv);
}
FindListViewItem(VisualTreeHelper.GetChild(obj as DependencyObject, i));
}
}
private void HighlightText(Object itx)
{
if (itx != null)
{
if (itx is TextBlock)
{
Regex regex = new Regex("(" +TxtSearch.Text + ")", RegexOptions.IgnoreCase);
TextBlock tb = itx as TextBlock;
if (TxtSearch.Text.Length == 0)
{
string str = tb.Text;
tb.Inlines.Clear();
tb.Inlines.Add(str);
return;
}
string[] substrings = regex.Split(tb.Text);
tb.Inlines.Clear();
foreach (var item in substrings)
{
if (regex.Match(item).Success)
{
Run runx = new Run(item);
runx.Background = Brushes.Lime;
tb.Inlines.Add(runx);
if (tb.IsMouseOver)
{
tb.IsEnabled = false;
}
}
else
{
tb.Inlines.Add(item);
tb.IsEnabled = false;
}
}
return;
}
else
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(itx as DependencyObject); i++)
{
HighlightText(VisualTreeHelper.GetChild(itx as DependencyObject, i));
}
}
}
}
答案 0 :(得分:2)
这是因为ListView默认使用虚拟化作为其内容。这意味着ListViewItems在需要时创建。如果您没有滚动ListView,则不会创建一些ListViewItems,并且VisualTreeHelper.GetChildrenCount将无法返回那些ListViewItems。
要实现您的目标,您可以:
VirtualizingStackPanel.IsVirtualizing="False"
来禁用ListView虚拟化(如果列表中有许多项目,则不建议这样做)。 IItemContainerGenerator.GenerateNext
和IItemContainerGenerator.PrepareItemContainer
(根本不推荐)来强制创建看不见的ListViewItem。 (另请查看this)答案 1 :(得分:0)
您可以通过多种方式完成此操作。以下是我认为可以在您的方案中使用的一种方法,部分使用您的代码并仍然使用虚拟化。
使用数据模板作为列表视图项,并为加载的事件创建事件处理程序,如:
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Loaded="FrameworkElement_OnLoaded"/>
</DataTemplate>
</ListView.ItemTemplate>
在OnLoaded事件处理程序中,在发件人上调用HighlightText方法:
HighlightText(sender)
为了触发加载的事件,每次搜索字符串发生变化时,您都需要刷新列表视图。像ListView.Items.Refresh()
之类的东西应该这样做。
您可以通过在更改的搜索文本上添加一个小计时器来改善这一点,这样用户就可以在搜索某些内容时完成输入。
还有其他更优雅的方法来处理这个问题,但对于你的情况,我认为这应该有用。
答案 2 :(得分:0)
除了我的评论:
使用Property和Observable Collection并直接过滤该Collection。
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<Entry> MyCollection {get;set;}
public MainWindow()
{
InitializeComponent();
MyCollection = new ObservableCollection<Entry>();
MyCollection.Add(new Entry() { Name = "Test" });
MyCollection.Add(new Entry() { Name = "ABCD" });
MyCollection.Add(new Entry() { Name = "TESTABC" });
MyCollection.Add(new Entry() { Name = "BCDtest" });
this.MyListView.DataContext = this;
}
private void searchTerm_KeyUp(object sender, KeyEventArgs e)
{
String term = ((TextBox)sender).Text;
foreach (Entry entry in this.MyCollection)
{
if (entry.Name.Contains(term))
entry.Highlight();
else
entry.UnHighlight();
}
}
}
public class Entry : INotifyPropertyChanged
{
public String Name { get; set; }
public Color BGColor { get; set; }
public SolidColorBrush BGBrush
{
get
{
return new SolidColorBrush(this.BGColor);
}
}
public Entry()
{
this.UnHighlight();
}
public void Highlight()
{
this.BGColor = Colors.Yellow;
this.NotifyPropertyChanged("BGBrush");
}
public void UnHighlight()
{
this.BGColor = Colors.White;
this.NotifyPropertyChanged("BGBrush");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
与
一起<Grid>
<DockPanel>
<TextBox DockPanel.Dock="Top" Name="searchTerm" KeyUp="searchTerm_KeyUp"></TextBox>
<ListView Name="MyListView" ItemsSource="{Binding MyCollection}" >
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Background="{Binding BGBrush}" Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DockPanel>
</Grid>
你完成了。无需随时手动触摸列表视图。 (提高性能:对于PropertyChanged事件的提升,您可能需要添加一个支票,如果它真的发生了变化,或者它是否已从白色等设置为白色。)