使用MVVMCross实现UISearchController

时间:2019-03-20 20:33:36

标签: xamarin xamarin.ios mvvmcross

我有一个应用程序,正在使用MVVMCross从iOS仅转换为iOS&Droid。

在我当前的应用程序中,我有一个使用UISearchController的地图视图,该视图允许用户搜索附近的位置。这基于Xamarin示例,效果很好: Xamarin Map Example

对于转换,我有:

  1. 绑定到MapViewModel的MapView。
  2. 已插入MapViewModel中的搜索服务。
  3. 创建了一个UISearchController并将搜索文本绑定到MapViewModel上的一个属性。

更新文本后,将调用搜索并检索结果。我正在努力的是如何将结果绑定回SearchResultsView,如UISearchController所示。

任何人都可以给我建议或指出正确的方向来解决这个问题。

下面是我的代码段,以了解到目前为止我所依赖的内容。

    [MvxFromStoryboard]
public partial class MapView : MvxViewController<MapViewModel>
{


    public MapView(IntPtr handle) : base(handle)
    {
    }

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

        var searchResultsController = new SearchResultsView();

        //Not sure if this is required
        //var searchUpdater.UpdateSearchResults += searchResultsController.Search;

        var searchController = new UISearchController(searchResultsController)
        {
            //Nore sure if this is required
            //SearchResultsUpdater = searchUpdater
        };


        searchController.SearchBar.SizeToFit();
        searchController.SearchBar.SearchBarStyle = UISearchBarStyle.Minimal;
        searchController.SearchBar.Placeholder = "Enter a search query";
        searchController.HidesNavigationBarDuringPresentation = false;
        DefinesPresentationContext = true;
        NavigationItem.TitleView = searchController.SearchBar;

        //Bind to View Model
        var set = this.CreateBindingSet<MapView, MapViewModel>();
        set.Bind(searchController.SearchBar).To(vm => vm.SearchQuery);
        set.Apply();
    }

}

public class SearchResultsUpdator : UISearchResultsUpdating
{
    public event Action<string> UpdateSearchResults = delegate { };

    public override void UpdateSearchResultsForSearchController(UISearchController searchController)
    {
        this.UpdateSearchResults(searchController.SearchBar.Text);
    }
}


[MvxFromStoryboard]
public partial class SearchResultsView : MvxTableViewController<SearchResultsViewModel>
{
    public SearchResultsView() { }

    public SearchResultsView(IntPtr handle) : base(handle)
    {
    }

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

        var source = new SearchResultsTableViewSource(TableView);
        TableView.Source = source;

        var set = this.CreateBindingSet<SearchResultsView, SearchResultsViewModel>();
        set.Bind(source).To(vm => vm.Results);
        set.Apply();


    }
}

[MvxFromStoryboard]
public partial class SearchResultsView : MvxTableViewController<SearchResultsViewModel>
{
    public SearchResultsView() { }

    public SearchResultsView(IntPtr handle) : base(handle)
    {
    }

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

        var source = new SearchResultsTableViewSource(TableView);
        TableView.Source = source;

        var set = this.CreateBindingSet<SearchResultsView, SearchResultsViewModel>();
        set.Bind(source).To(vm => vm.Results);
        set.Apply();


    }
}

1 个答案:

答案 0 :(得分:0)

如果有人正在寻找示例,我已经发布了此信息。我决定最好的方法是让iOS处理结果的搜索视图控制器。代码如下。随时纠正或提出更好的选择

查看

    [MvxFromStoryboard]
    public partial class MapView : MvxViewController
    {
        UISearchController _searchController;
        SearchResultsViewController _searchResultsController;

        private IDisposable _searchResultsUpdateSubscription;
        private IMvxInteraction _searchResultsUpdatedInteraction;
        public IMvxInteraction SearchResultsUpdatedInteraction
        {
            get => _searchResultsUpdatedInteraction;
            set
            {
                if (_searchResultsUpdateSubscription != null)
                {
                    _searchResultsUpdateSubscription.Dispose();
                    _searchResultsUpdateSubscription = null;
                }

                _searchResultsUpdatedInteraction = value;
                if (_searchResultsUpdatedInteraction != null)
                {
                    _searchResultsUpdateSubscription = _searchResultsUpdatedInteraction.WeakSubscribe(OnSearchResultsUpdated);
                }
            }
        }


        private void OnSearchResultsUpdated(object sender, EventArgs e)
        {
            _searchResultsController.SearchResults = Results;
            _searchResultsController.ReloadSearchTable();
        }

        public List<Placemark> Results { get; set; }

        public MapView(IntPtr handle) : base(handle)
        {
        }

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

            //Bind to View Model
            var set = this.CreateBindingSet<MapView, MapViewModel>();
            set.Bind(_searchController.SearchBar).To(vm => vm.SearchQuery);
            set.Bind(this).For(v => v.Results).To(vm => vm.Results);
            set.Bind(this).For(v => v.SearchResultsUpdatedInteraction).To(vm => vm.SearchResultsUpdatedInteraction).OneWay();
            set.Apply();

        }

ViewModel

    public class MapViewModel : MvxViewModel
    {
        readonly ILocationService _locationService;

        private MvxInteraction _searchResultsUpdatedInteraction = new MvxInteraction();
        public IMvxInteraction SearchResultsUpdatedInteraction => _searchResultsUpdatedInteraction;

        public MapViewModel(ILocationService locationService)
        {
            _locationService = locationService;
        }
        //***** Properties *****

        private List<Placemark> _results;
        public List<Placemark> Results
        {
            get => _results;
            set
            {
                _results = value;
                RaisePropertyChanged();
            }
        }

        private string _searchQuery;
        public string SearchQuery
        {
            get => _searchQuery;
            set
            {
                _searchQuery = value;
                //Task.Run(UpdateResultsAsync).Wait();
                RaisePropertyChanged();
                UpdateResultsAsync();
            }
        }

        //***** Privates *****
        private async Task UpdateResultsAsync()
        {
            Results = await _locationService.SearchForPlacesAsync(_searchQuery);
            _searchResultsUpdatedInteraction.Raise();
        }
    }

SearchResultsViewController

    public class SearchResultsViewController : UITableViewController
    {
        static readonly string mapItemCellId = "mapItemCellId";

        public List<Placemark> SearchResults { get; set; }

        public SearchResultsViewController()
        {

            SearchResults = new List<Placemark>();
        }

        public override nint RowsInSection(UITableView tableView, nint section)
        {
            return SearchResults == null ? 0 : SearchResults.Count;
        }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            var cell = tableView.DequeueReusableCell(mapItemCellId);

            if (cell == null)
                cell = new UITableViewCell();

            cell.TextLabel.Text = SearchResults[indexPath.Row].FeatureName;
            return cell;
        }

        public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
        {
           //Do stuff here
        }

        public void ReloadSearchTable()
        {
            this.TableView.ReloadData();
        }
    }