You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于MvvmCross(Xamarin.iOS)的车次查询项目UITextField跳转需求求助

Hey there! Let's walk through implementing this station selection flow for your MvvmCross Xamarin.iOS train query app. This solution follows MvvmCross's MVVM patterns to keep your code clean and maintainable:

1. ViewModel Layer Setup

First, we'll create two view models: one for your main query screen, and another for the station selection list.

1.1 Main Query ViewModel (e.g., TrainQueryViewModel)

This view model handles triggering navigation to the station picker and receiving the selected station to update the text field's bound property.

public class TrainQueryViewModel : MvxViewModel
{
    private readonly IMvxNavigationService _navigationService;
    private string _departureStation;

    public string DepartureStation
    {
        get => _departureStation;
        set => SetProperty(ref _departureStation, value);
    }

    public IMvxCommand OpenStationPickerCommand { get; }

    public TrainQueryViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService;
        OpenStationPickerCommand = new MvxAsyncCommand(OpenStationPickerAsync);
    }

    private async Task OpenStationPickerAsync()
    {
        // Navigate to station picker and await the selected station result
        var selectedStation = await _navigationService.Navigate<StationSelectionViewModel, string>();
        
        if (!string.IsNullOrEmpty(selectedStation))
        {
            DepartureStation = selectedStation;
        }
    }
}

1.2 Station Selection ViewModel (e.g., StationSelectionViewModel)

This view model holds the list of stations and handles returning the selected station to the main view model.

public class StationSelectionViewModel : MvxViewModel<string>
{
    private readonly IMvxNavigationService _navigationService;
    private List<string> _stations;

    public List<string> Stations
    {
        get => _stations;
        set => SetProperty(ref _stations, value);
    }

    public IMvxCommand<string> SelectStationCommand { get; }

    public StationSelectionViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService;
        SelectStationCommand = new MvxAsyncCommand<string>(SelectStationAsync);
        
        // Load your actual station data here (replace with your data source)
        Stations = new List<string> { "Beijing South", "Shanghai Hongqiao", "Guangzhou South", "Shenzhen North" };
    }

    private async Task SelectStationAsync(string station)
    {
        // Return the selected station to the previous view model
        await _navigationService.Close(this, station);
    }
}
2. iOS View Layer Implementation

Now let's wire up the iOS views to work with our view models.

2.1 Main Query View (e.g., TrainQueryView)

We'll bind the UITextField to the DepartureStation property, and add a trigger to launch the station picker when the text field is tapped.

public class TrainQueryView : MvxViewController<TrainQueryViewModel>
{
    private UITextField _departureTextField;

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        
        // Initialize text field (adjust layout constraints as needed for your app)
        _departureTextField = new UITextField
        {
            Frame = new CGRect(20, 100, View.Bounds.Width - 40, 40),
            BorderStyle = UITextBorderStyle.RoundedRect,
            Placeholder = "Select departure station"
        };
        View.AddSubview(_departureTextField);

        // Bind text field content to view model property
        var bindingSet = this.CreateBindingSet<TrainQueryView, TrainQueryViewModel>();
        bindingSet.Bind(_departureTextField).To(vm => vm.DepartureStation);
        bindingSet.Apply();

        // Disable default keyboard since we're using the text field to trigger navigation
        _departureTextField.InputView = new UIView();

        // Add tap gesture to launch station picker
        var tapGesture = new UITapGestureRecognizer(() => 
            ViewModel.OpenStationPickerCommand.Execute());
        _departureTextField.AddGestureRecognizer(tapGesture);

        // Alternative: Use EditingDidBegin event to trigger navigation
        _departureTextField.EditingDidBegin += (s, e) =>
        {
            ViewModel.OpenStationPickerCommand.Execute();
            _departureTextField.ResignFirstResponder();
        };
    }
}

2.2 Station Selection View (e.g., StationSelectionView)

We'll use an MvxTableView to display stations, bind the list data, and handle selection via the view model command.

public class StationSelectionView : MvxViewController<StationSelectionViewModel>
{
    private MvxTableView _stationsTableView;

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        Title = "Select Station";

        // Initialize table view
        _stationsTableView = new MvxTableView(View.Bounds);
        _stationsTableView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
        View.AddSubview(_stationsTableView);

        // Bind table view to view model data and command
        var bindingSet = this.CreateBindingSet<StationSelectionView, StationSelectionViewModel>();
        bindingSet.Bind(_stationsTableView)
           .For(v => v.Source)
           .To(vm => vm.Stations);
        bindingSet.Bind(_stationsTableView)
           .For(v => v.SelectedItem)
           .To(vm => vm.SelectStationCommand);
        bindingSet.Apply();

        // Register and configure table view cell
        _stationsTableView.RegisterClassForCellReuse(typeof(UITableViewCell), "StationCell");
        _stationsTableView.Source = new MvxSimpleTableViewSource(
            _stationsTableView, 
            "StationCell", 
            UITableViewCellStyle.Default, 
            nameof(UITableViewCell.TextLabel), 
            nameof(UITableViewCell.TextLabel.Text));
    }
}
3. Navigation Registration

Don't forget to register your views and view models in your Setup.cs so MvvmCross can resolve them:

public class Setup : MvxIosSetup<App>
{
    protected override void InitializeViewLookup()
    {
        base.InitializeViewLookup();
        var viewLookup = new Dictionary<Type, Type>
        {
            { typeof(TrainQueryViewModel), typeof(TrainQueryView) },
            { typeof(StationSelectionViewModel), typeof(StationSelectionView) }
        };
        Mvx.IoCProvider.RegisterSingleton<IMvxViewsContainer>(new MvxViewsContainer(viewLookup));
    }
}

This implementation sticks to MvvmCross best practices:

  • Uses IMvxNavigationService for clean, view-model-first navigation
  • Leverages view model result return to pass data between screens without tight coupling
  • Binds UI elements directly to view model properties/commands to keep business logic out of views

内容的提问来源于stack exchange,提问作者HoereeBauke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:02:48