1

顧客情報を含むリストビューがあります。そのリストビューの上に検索テキストボックスがあります。テキストボックスに何かを入力すると、リストビューで一致したアイテムが強調表示されます。しかし、問題は、リストビューの視覚的な側面でのみ検索を行うことです。リストビューのスクロールされていない側(リストビューの下部)は検索されません。私のコードは以下の通りです。ご覧ください。

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));
            }
        }
    }
}
4

3 に答える 3

2

これは、ListView が既定でそのコンテンツに仮想化を使用するために発生します。これは、ListViewItems が必要なときに作成されることを意味します。ListView をスクロールしなかった場合、一部の ListViewItems は作成されず、VisualTreeHelper.GetChildrenCount はそれらの ListViewItems を返すことができません。

目的を達成するために、次のことができます。

  • ListView で次のように設定して、ListView の仮想化を無効VirtualizingStackPanel.IsVirtualizing="False"にします (リストに多くのアイテムがある場合はお勧めしません)。
  • IItemContainerGenerator.GenerateNextandを呼び出すことで表示されない ListViewItem の作成を強制できますIItemContainerGenerator.PrepareItemContainer(まったくお勧めしません)。(こちらもご覧ください
  • ListViewItems を強調表示するためのより良いロジックを見つけてください :) (推奨)。(たとえば、アイテムのみを表示している UI 要素を検索するのではなく、ハイライトしたいアイテムをコレクションで検索します。次に、見つかったアイテムをハイライト表示としてマークし、これに基づいて、それに応じて ListViewItems を表示します (別のテンプレートまたはスタイル))
于 2012-12-05T10:06:57.500 に答える
0

私のコメントに加えて:

プロパティと監視可能なコレクションを使用し、そのコレクションを直接フィルタリングします。

/// <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 イベントの発生について、実際に変化する場合、または白から白に設定されている場合などに、チェックを追加することをお勧めします。)

于 2012-12-05T13:59:24.747 に答える
0

これはいくつかの方法で行うことができます。これは、シナリオで機能し、コードで部分的に機能し、仮想化を引き続き使用すると思われる1つの方法です。

リスト ビュー アイテムのデータ テンプレートを使用し、読み込まれたイベントのイベント ハンドラーを次のように作成します。

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

OnLoaded イベント ハンドラーで、送信側で HighlightText メソッドを呼び出します。

HighlightText(sender)

ロードされたイベントをトリガーするには、検索文字列が変更されるたびにリスト ビューを更新する必要があります。のような何かListView.Items.Refresh()がそれを行う必要があります。

変更された検索テキストに小さなタイマーを追加することで、これを少し改善できます。これにより、ユーザーは何かを検索しているときに入力を終了できるようになります。

これを処理する他のよりエレガントな方法がありますが、あなたの場合はこれでうまくいくはずです。

于 2012-12-05T13:26:54.067 に答える