2012-12-05 62 views
1

我有一個包含客戶信息的listview。該列表視圖上方有一個搜索文本框。當你在文本框中輸入任何內容時,它會在列表視圖中突出顯示匹配的項目。但是,問題在於它只能在列表視圖的視覺方面進行搜索。它不會在列表視圖的不滾動的一側進行搜索(listview的按鈕)。我的代碼如下。請看一看。WPF Listview item highlighting

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

此外,默認情況ListView控件使用虛擬化,這意味着並不是所有的項目都被繪製出來,所以你的方法在這種情況下是行不通的。 –

+0

正在使用MVVM方法嗎?你有綁定視圖模型? – Sisyphe

+0

@AdrianFaciu那麼你有什麼建議嗎? – Omnipotent

回答

2

發生這種情況是因爲默認情況下,ListView將虛擬化用於其內容。這意味着ListViewItems在需要時被創建。如果您沒有滾動ListView,則不會創建一些ListViewItems,並且VisualTreeHelper.GetChildrenCount將無法返回這些ListViewItems。

達到你想要什麼,你可以:

  • 通過設置禁用的ListView虛擬化:VirtualizingStackPanel.IsVirtualizing="False"您的ListView(不推薦,如果你在你的列表中有許多項目)。
  • 您可以通過調用IItemContainerGenerator.GenerateNextIItemContainerGenerator.PrepareItemContainer(根本不推薦)來強制創建ListViewItem。 (也看看this
  • 找到一個更好的邏輯來突出你的ListViewItems :)(推薦)。 (例如,在您的收藏集中搜索要突出顯示的項目,而不是在僅顯示項目的UI元素上搜索,然後將找到的項目標記爲突出顯示並基於此項目,相應地顯示ListView項目(使用不同的模板或樣式))
+0

我已經應用您的第一個解決方案。它可以工作,但效果不是很好:D正如你所說,我列表中的項目太多,因此無法正常工作。我不能申請第二個:)最後一個是我不想讓它:) – Omnipotent

+0

+ 1,推薦的方法是按照不同的方法突出顯示的項目,禁用虛擬化通常要求麻煩 –

0

您可以通過多種方式實現此目的。以下是我認爲可以在您的方案中工作的一種方法,部分方法是使用您的代碼並仍然使用虛擬化。

使用列表視圖項的數據模板,並創建加載事件的事件處理程序,是這樣的:

<ListView.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding}" Loaded="FrameworkElement_OnLoaded"/> 
     </DataTemplate> 
</ListView.ItemTemplate> 

在裝載的事件處理程序調用上的發件人的HighlightText方法:

HighlightText(sender) 

爲了觸發加載的事件,每當搜索字符串發生變化時,您都需要刷新列表視圖。像ListView.Items.Refresh()應該這樣做。

您可以通過在更改的搜索文本上添加一個小計時器來改善這一點,以便用戶在搜索某些內容時能夠完成打字。

還有其他的,更優雅的方式來處理這個問題,但對於你的情況,我認爲這應該工作。

0

除了我的評論:

使用一個屬性和一個Observable集合,並直接篩選該集合。

/// <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事件的提出可能要增加一個檢查,如果它真的發生變化,或者如果它已經從白色等設置爲白色)

+0

Isn'這將突出顯示整個項目,與搜索詞無關嗎?據我瞭解,OP正在嘗試僅選擇與搜索詞匹配的部分。 –

+0

@AdrianFaciu他寫道'然後它在listview'中強調匹配的項目。所以我認爲整個項目是他想要的。 – dognose