Question

I was just wondering if there is any example of how this would be done?

So what I am trying to do is implement a search with MVVCross and don't really now how to start. Any tips on right directions would be greatly appriciated.

As what is worth, my thinking goes somewhat like that...

I have one view, where I have the search bar. But I am not searching through data in that view. So on search, I would like to display a new table view and search through it.

I have created a cell for the table and controller to display it (just the usuall list view stuff), but am now stuck with search bar implementation.

public partial class HomeView : MvxViewController
{
    public HomeView () : base ("HomeView", null)
    {
    }

    public override void DidReceiveMemoryWarning ()
    {
        // Releases the view if it doesn't have a superview.
        base.DidReceiveMemoryWarning ();

        // Release any cached data, images, etc that aren't in use.
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        if (RespondsToSelector(new MonoTouch.ObjCRuntime.Selector("edgesForExtendedLayout")))
            EdgesForExtendedLayout = UIRectEdge.None;
        RecommendedCollectionView.RegisterNibForCell(RecommededStationCollectionCell.Nib, RecommededStationCollectionCell.Key);
        var source = new MvxCollectionViewSource(RecommendedCollectionView, RecommededStationCollectionCell.Key);
        RecommendedCollectionView.Source = source;

        var set = this.CreateBindingSet<HomeView, HomeViewModel>();
        set.Bind(source).To(vm => vm.Genres);
        set.Apply();
        RecommendedCollectionView.ReloadData();
        var gesture = new UITapGestureRecognizer (() => {

        });

        View.AddGestureRecognizer (gesture);
    }
}

And list view:

public class SearchView : UITableViewController
{
    public SearchView () : base ("SearchView", null)
    {
    }

    public override void DidReceiveMemoryWarning ()
    {
        // Releases the view if it doesn't have a superview.
        base.DidReceiveMemoryWarning ();

        // Release any cached data, images, etc that aren't in use.
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();


        var source = new MvxSimpleTableViewSource (TableView, SearchTableCell.Key, SearchTableCell.Key);
        TableView.Source = source;
        TableView.RowHeight = 50;

        var set = this.CreateBindingSet<SearchView, SearchViewModel> ();
        set.Bind (source).To (vm => vm.Genres);
        set.Apply ();
        TableView.ReloadData ();
        // Perform any additional setup after loading the view, typically from a nib.
    }
}

So to sum it up, what I want is when user inputs something in searchbar in home view, to show searchView list and search through the data inside.

Thanks.

Was it helpful?

Solution

Thanks guys. Sorry for late response on my sight, all those answers help me to understand MVVMCross better. So at the end, I ended up with this solution. If there are some conserns about this approach, I would be happy if one could point it out.

So in view model, I have a string propery, which is bind to searh text. And whenever there is a text change, I filter the list as well.

So view model looks something like that:

    private string _searchTerm;
    public string SearchTerm 
    {
        get { return _searchTerm; }
        set { 
            _searchTerm = value; 
            if (String.IsNullOrEmpty(_searchTerm)) {
                _genres = new List<Genre> ();
            } else {
                _genres = allGenres.Where (g => g.Name.ToLower ().Contains (_searchTerm.ToLower ())).ToList ();
            }
            RaisePropertyChanged (() => SearchTerm);
            RaisePropertyChanged (() => Genres);
        }
    }

And then in view its just binding it :

set.Bind (SearchBar).For (x=>x.Text).To (vm => vm.SearchTerm);

And of course, the list is bind to table source. That is all there is to it.

OTHER TIPS

Not sure if this is what you are looking for. I did something similar, when the user starts typing I was refreshing the list that was being displayed to the user. Not sure if its really what your looking for but it worked for me.

/// <summary>
    /// Views the did load.
    /// </summary>
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        _searchBar = new UISearchBar(new RectangleF(0, 0, 320, 44))
        {
            AutocorrectionType = UITextAutocorrectionType.Yes
        };
        _searchBar.SearchButtonClicked += SearchBar_SearchButtonClicked;
        _searchBar.TextChanged += SearchBarOnTextChanged;
        _searchBar.CancelButtonClicked += SearchBarOnCancelButtonClicked;

        var source = new MvxSimpleTableViewSource (TableView, SpeciesListCellView.Key, SpeciesListCellView.Key);

        var set = this.CreateBindingSet<SpeciesListView, SpeciesListViewModel> ();
        set.Bind(source).To(vm => vm.Species);

        set.Apply ();

        TableView.RowHeight = 50;
        TableView.Source = source;
        TableView.TableHeaderView = _searchBar;
        TableView.ReloadData ();
    }

Then I wired up the handlers

        /// <summary>
    /// Searches the bar on cancel button clicked.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="eventArgs">The <see cref="EventArgs"/> instance containing the event data.</param>
    private void SearchBarOnCancelButtonClicked(object sender, EventArgs eventArgs)
    {
        ((SpeciesListViewModel)ViewModel).SearchSpecieByText(string.Empty);
        BeginInvokeOnMainThread(() => _searchBar.ResignFirstResponder());
    }

    /// <summary>
    /// Searches the bar on text changed.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="UISearchBarTextChangedEventArgs"/> instance containing the event data.</param>
    private void SearchBarOnTextChanged(object sender, UISearchBarTextChangedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(_searchBar.Text))
        {
            ((SpeciesListViewModel)ViewModel).SearchSpecieByText(string.Empty);

            BeginInvokeOnMainThread(() => _searchBar.ResignFirstResponder());
        }
        else
        {
            ((SpeciesListViewModel)ViewModel).SearchSpecieByText(_searchBar.Text);
        }
    }

    /// <summary>
    /// Handles the SearchButtonClicked event of the SearchBar control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    private void SearchBar_SearchButtonClicked(object sender, EventArgs e)
    {
        ((SpeciesListViewModel)ViewModel).SearchSpecieByText(_searchBar.Text);
        BeginInvokeOnMainThread(() => _searchBar.ResignFirstResponder());
    }

Then in my ViewModel i was just refreshing the list, making sure you keep a full copy of the original list.

        /// <summary>
    /// Searches the specie by text.
    /// </summary>
    /// <param name="text">The text.</param>
    public void SearchSpecieByText(string text)
    {
        if (string.IsNullOrWhiteSpace(text))
            Species = FullSpeciesList;
        else
        {
            Species = FullSpeciesList;
            Species = Species.Where(m => m.Name.ToLowerInvariant().Contains(text.ToLowerInvariant())).ToList();
        }
    }

and then property Species would then call the RaisePropertyChanged method

adding onto Lipton's answer: if you want the search to happen on VM,

option 1) Have an observable dictionary as the source, and as it updates, it would raise an event for mvx (a bit too expensive for my taste)

option 2) Have a normal source, and upon filtering, raise some kind of event in VM (like a weak message) which would then force the view to reload data (can't remember the exact syntax, but it's along the lines of Table.ReloadData)

Doing it on View side: simpler, as you just filter and update data source, and reloadData again.

Warning: remember to unwire any events you have subscribed to on your search-bar; ideally instead of wiring it on ViewDidLoad, you should use ViewWillAppear, and unwire when ViewDidDisappear

also, searchBar can have a delegate set (_searchBar.Delegate = ), which I think is a bit cleaner, as you only have one thing to set null instead of multiple;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top