You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Xamarin.Android中通过ReactiveUI正确绑定ReactiveList到Spinner?

问题分析与解决方案

看起来你在使用ReactiveUI绑定Xamarin.Android Spinner时踩了几个典型的坑,我帮你梳理下问题点,再给出正确的实现方式:

你代码里的核心问题

  1. 错误使用Bind方法Bind的设计是用来绑定ViewModel属性到UI控件的属性(比如把ViewModel的字符串绑定到TextView的Text),但你却把它绑定到了Fragment里的本地ExampleList变量——这个变量和UI毫无关联,ViewModel列表变化时自然不会触发UI更新。
  2. 本地ExampleList完全多余:你在action里引用的是这个未赋值的本地列表,根本拿不到ViewModel里的真实数据,这也是绑定没生效的关键原因。
  3. ViewModel列表未初始化:如果ExampleList没有在构造函数里初始化,它会一直是null,ReactiveUI无法监听到任何变化。

正确实现步骤

第一步:修正ViewModel

确保列表初始化并开启变化追踪(如果需要监听列表内元素的增删):

public class ExampleVM : ReactiveObject
{
    private ReactiveList<ExampleTypeResult> _exampleList;

    public ReactiveList<ExampleTypeResult> ExampleList
    {
        get => _exampleList;
        private set => this.RaiseAndSetIfChanged(ref _exampleList, value);
    }

    public ExampleVM()
    {
        // 初始化列表,避免null
        ExampleList = new ReactiveList<ExampleTypeResult>();
        // 开启元素变化追踪(可选,如果你需要监听列表内元素增删)
        ExampleList.ChangeTrackingEnabled = true;
    }
}

第二步:Fragment里的正确绑定

直接监听ViewModel的列表变化,动态更新Spinner的Adapter:

public class ExampleFragment : ExampleBaseFragment<ExampleVM>
{
    private Spinner _fragmentExampleSpinner;

    public override void OnViewCreated(View view, Bundle savedInstanceState)
    {
        base.OnViewCreated(view, savedInstanceState);
        
        // 初始化Spinner控件(根据你的布局方式调整,比如视图绑定或FindViewById)
        _fragmentExampleSpinner = view.FindViewById<Spinner>(Resource.Id.FragmentExampleSpinner);

        // 监听ViewModel列表的整体变化(比如列表被重新赋值)
        this.WhenAnyValue(x => x.ViewModel.ExampleList)
            .Where(list => list != null)
            .Subscribe(list => UpdateSpinnerAdapter(list))
            .DisposeWith(SubscriptionDisposables);

        // 可选:监听列表内元素的增删变化,实时刷新Adapter
        this.WhenAnyValue(x => x.ViewModel.ExampleList)
            .SelectMany(list => list.Changed)
            .Subscribe(_ => UpdateSpinnerAdapter(ViewModel.ExampleList))
            .DisposeWith(SubscriptionDisposables);
    }

    // 封装更新Adapter的逻辑,避免重复代码
    private void UpdateSpinnerAdapter(ReactiveList<ExampleTypeResult> list)
    {
        var itemNames = list.Select(item => item._Name).ToList();
        var adapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleSpinnerItem, itemNames);
        adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
        _fragmentExampleSpinner.Adapter = adapter;
    }
}

额外:双向绑定(如果需要)

如果要把用户选择的Spinner项同步回ViewModel,可以添加这段绑定:

// 假设ViewModel有一个SelectedExample属性用于存储选中项
this.Bind(ViewModel, vm => vm.SelectedExample, v => v._fragmentExampleSpinner.SelectedItem)
    .DisposeWith(SubscriptionDisposables);

补充建议

  • 如果你使用的是较新版本的ReactiveUI,推荐用ObservableCollection<T>替代ReactiveList<T>(ReactiveList已被标记为过时),用法几乎一致,只需要把ReactiveList替换成ObservableCollection即可。
  • 确保Spinner控件已经正确初始化,否则设置Adapter也不会有任何效果。

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

火山引擎 最新活动