|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;
using CodeMind.FirefoxLikeSearch.Infrastructure;
namespace CodeMind.FirefoxLikeSearch.ViewModels
{
internal class SearchViewModel<T> : ViewModel where T : class
{
private enum SearchType
{
Forward,
ForwardSkipCurrent,
Backward
}
private readonly Func<T, string, bool> _itemMatch;
private bool _noResults;
private string _searchTerm = String.Empty;
/// <summary>
/// Creates a new instance of <see cref="SearchViewModel{T}"/> class.
/// </summary>
/// <param name="collectionView">Collection to search for items.</param>
/// <param name="itemMatch">Delegate to perform item matching.</param>
public SearchViewModel(ICollectionView collectionView, Func<T, string, bool> itemMatch)
{
CollectionView = collectionView;
CollectionView.CollectionChanged += (sender, e) => RebuildSearchIndex();
RebuildSearchIndex();
_itemMatch = itemMatch;
NextCommand = new DelegateCommand(
p => FindItem(SearchType.ForwardSkipCurrent),
x => !String.IsNullOrEmpty(SearchTerm) && !NoResults);
PreviousCommand = new DelegateCommand(
p => FindItem(SearchType.Backward),
x => !String.IsNullOrEmpty(SearchTerm) && !NoResults);
}
protected ICollectionView CollectionView { get; private set; }
protected IList<T> SearchIndex { get; private set; }
public ICommand NextCommand { get; private set; }
public ICommand PreviousCommand { get; private set; }
public bool NoResults
{
get { return _noResults; }
set
{
if (_noResults == value) return;
_noResults = value;
OnPropertyChanged("NoResults");
}
}
public string SearchTerm
{
get { return _searchTerm; }
set
{
if (_searchTerm == value) return;
_searchTerm = value;
OnPropertyChanged("SearchTerm");
NoResults = false;
FindItem(SearchType.Forward);
}
}
private void FindItem(SearchType type)
{
if (String.IsNullOrEmpty(SearchTerm)) return;
T item;
switch (type)
{
case SearchType.Forward:
// Search from the current position to end and loop from start if nothing found
item = FindItem(CollectionView.CurrentPosition, SearchIndex.Count - 1) ??
FindItem(0, CollectionView.CurrentPosition);
break;
case SearchType.ForwardSkipCurrent:
// Search from the next item position to end and loop from start if nothing found
item = FindItem(CollectionView.CurrentPosition + 1, SearchIndex.Count - 1) ??
FindItem(0, CollectionView.CurrentPosition);
break;
case SearchType.Backward:
// Search backwards from the current position to start and loop from end if nothing found
item = FindItemReverse(CollectionView.CurrentPosition - 1, 0) ??
FindItemReverse(SearchIndex.Count - 1, CollectionView.CurrentPosition);
break;
default:
throw new ArgumentOutOfRangeException("type");
}
if (item == null)
NoResults = true;
else
CollectionView.MoveCurrentTo(item);
}
private T FindItem(int startIndex, int endIndex)
{
for (var i = startIndex; i <= endIndex; i++)
{
if (_itemMatch(SearchIndex[i], SearchTerm))
return SearchIndex[i];
}
return null;
}
private T FindItemReverse(int startIndex, int endIndex)
{
for (var i = startIndex; i >= endIndex; i--)
{
if (_itemMatch(SearchIndex[i], SearchTerm))
return SearchIndex[i];
}
return null;
}
private void RebuildSearchIndex()
{
SearchIndex = new List<T>();
foreach (var item in CollectionView)
{
SearchIndex.Add((T) item);
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.