Skip to content

Instantly share code, notes, and snippets.

@kjeremy
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kjeremy/5cb27c19787789e0b1db to your computer and use it in GitHub Desktop.
Save kjeremy/5cb27c19787789e0b1db to your computer and use it in GitHub Desktop.
Adapter for SearchView
public abstract class SearchFilterAdapterBase : MvxAdapter, IFilterable
{
protected SearchFilterAdapterBase(Context context)
: base(context) {}
protected SearchFilterAdapterBase(Context context, IMvxAndroidBindingContext bindingContext)
: base(context, bindingContext) {}
protected abstract Filter CreateFilter();
private Filter _filter;
public Filter Filter
{
get { return this._filter ?? (this._filter = this.CreateFilter()); }
}
private readonly object _lock = new object();
public object Lock
{
get { return this._lock; }
}
[MvxSetToNullAfterBinding]
public IEnumerable FilteredSubset { get; set; }
protected override void SetItemsSource(IEnumerable value)
{
lock (this.Lock)
{
this.FilteredSubset = null;
base.SetItemsSource(value);
}
}
public override int GetPosition(object item)
{
lock (this.Lock)
{
IEnumerable source = this.FilteredSubset ?? ItemsSource;
return MvxEnumerableExtensions.GetPosition(source, item);
}
}
public override object GetRawItem(int position)
{
lock (this.Lock)
{
IEnumerable source = this.FilteredSubset ?? ItemsSource;
return MvxEnumerableExtensions.ElementAt(source, position);
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
lock (this.Lock)
{
return base.GetView(position, convertView, parent);
}
}
public override int Count
{
get
{
lock (this.Lock)
{
return MvxEnumerableExtensions.Count(this.FilteredSubset ?? ItemsSource);
}
}
}
}
public class SearchFilter<T> : Filter
{
private readonly SearchFilterAdapterBase _adapter;
public SearchFilter(SearchFilterAdapterBase adapter)
{
this._adapter = adapter;
}
public Func<T, string, bool> SearchFunc { get; set; }
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
// If there is no constraint return the original data set
var returnObject = new FilterResults();
if (constraint == null || constraint.Length() == 0)
return returnObject;
var results = new List<T>();
try
{
lock (this._adapter.Lock)
{
if (this._adapter.ItemsSource.Count() > 0)
{
IEnumerable<T> source = this._adapter.ItemsSource as IEnumerable<T>;
if (source == null)
return returnObject;
string c = constraint.ToString();
results.AddRange(source.Where(o => this.SearchFunc(o, c)));
returnObject.Values = FromArray(results.Select(r => r.ToJavaObject()).ToArray());
returnObject.Count = results.Count;
}
}
}
catch (System.Exception ex)
{
throw;
var table = new Dictionary<string, string>();
try
{
table.Add("constraint handle", constraint.Handle.ToString());
if (constraint.Handle != IntPtr.Zero)
table.Add("constraint", constraint.ToString());
}
catch (System.Exception)
{
// Swallow
}
finally
{
Mvx.Resolve<IAppInsights>().Report(ex, table, ReportSeverity.Error);
}
throw;
}
finally
{
// Without the dispose GREFs go up, but maybe it contributes to the
// Java GC destroying constraint before we're done using it.
//constraint.Dispose();
}
return returnObject;
}
protected override void PublishResults(ICharSequence constraint, FilterResults results)
{
lock (this._adapter.Lock)
{
// Use the original data set if there is no constraint
if (this._adapter.ItemsSource.Count() == 0 || constraint == null || constraint.Length() == 0)
{
// When there is nothing in the items source make sure
// the filter is null.
this._adapter.FilteredSubset = null;
this._adapter.NotifyDataSetInvalidated();
}
else
{
using (var values = results.Values)
{
this._adapter.FilteredSubset = values.ToArray<Java.Lang.Object>()
.Select(r => r.ToNetObject<T>()).ToList();
}
}
this._adapter.NotifyDataSetChanged();
}
//constraint.Dispose();
//results.Dispose();
}
}
public override void OnCreateOptionsMenu(IMenu menu, MenuInflater inflater)
{
// The view pager sets this hint (through our parent fragment) so we need
// to figure out if the menu items are visible or not.
if (!UserVisibleHint)
return;
base.OnCreateOptionsMenu(menu, inflater);
inflater.Inflate(Resource.Menu.ListMenu, menu);
var searchMenu = menu.FindItem(Resource.Id.action_search);
this._searchView = MenuItemCompat.GetActionView(searchMenu).JavaCast<SearchView>();
this._searchView.QueryHint = "Search for assets.";
this._searchView.LayoutParameters = new ActionBar.LayoutParams(GravityFlags.Right);
this._searchView.QueryTextChange += (s, e) => { ViewModel.Constraint = e.NewText; };
this._searchView.QueryTextSubmit += (s, e) => { e.Handled = true; };
MenuItemCompat.SetOnActionExpandListener(searchMenu, new SearchViewExpandListener(this._adapter));
}
public string SearchTerm
{
get { return ViewModel.Constraint; /* just to make the compiler happy */ }
set
{
// Do not use string variant.
// See: https://bugzilla.xamarin.com/show_bug.cgi?id=25995
this._adapter.Filter.InvokeFilter(new Java.Lang.String(ViewModel.Constraint));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment