问题
I'm trying to bind to a Spinner using ReactiveUI in a Xamarin.Android application. To add items to the Spinner
, I need to use ArrayAdapter
. But ArrayAdapter
needs Android.Content.Context
. Should I pass it into the ViewModel?
Anyone know about an application written in Xamarin.Android, which uses ReactiveUI, where I could look inspiration? The ReactiveUI documentation only has a reference to a sample application written for iOS.
View
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/Label"
android:text="Zařízení:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Spinner
android:id="@+id/Devices"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/Label"/>
<Button
android:id="@+id/EditCommand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/Devices"
android:text="Edit"/>
</RelativeLayout>
Activity
namespace Test.Droid
{
[Activity(Label = "Test.Droid", MainLauncher = true)]
public class MainActivity : ReactiveActivity, IViewFor<MainViewModel>
{
public Spinner Devices { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
ViewModel = new MainViewModel();
this.WireUpControls();
// Bindings
this.Bind(this.ViewModel, ) // ?
}
private MainViewModel _viewModel;
public MainViewModel ViewModel
{ get => _viewModel; set { this.RaiseAndSetIfChanged(ref _viewModel, value); } }
object IViewFor.ViewModel
{ get => ViewModel; set { ViewModel = (MainViewModel)value; } }
}
}
ViewModel
namespace Test.Droid.ViewModels
{
public class MainViewModel : ReactiveObject
{
// How to databind Spinner Devices ?
public MainViewModel()
{
}
}
}
回答1:
I haven't done any Xamarin.Android development, but in general you don't want to pass details about the view into the ViewModel - it should not know anything about the view.
I would expose the list of items as a collection (e.g. IList<Item>
) and use a converter on the binding to create an ArrayAdapter
:
this.OneWayBind(this.ViewModel.Devices, this.View.Property, devices => new ArrayAdapter(devices));
this.View.Property
should refer to the property that changes whenever the list of devices changes. The third parameter (devices => new ArrayAdapter()
) receives the property from the ViewModel as an argument, you then return a value that can be set on the this.View.Property
.
For example:
ViewModel.Count
is astring
View.Property
is anint
Bind like this:
this.OneWayBind(this.ViewModel.Count, this.View.Property, count => int.Parse(count));
The third parameter can be a function or lambda that accepts an argument of the type of the ViewModel property and returns a value of the type of the view property.
回答2:
I'd said I'd given in providing any feedback on Stackoverflow but anyway... we have a collection of binding extensions, one of which is for a Spinner. in typical usage it looks like this
// bind the options for the distance
this.BindSpinner(ViewModel,
vm => vm.TravelLimitSelected,
vm => vm.CurrentTravelLimit,
vm => vm.TravelLimitChoices.Distances,
f => f.travelLimitSpinner,
(items) =>
new ActionSpinnerAdapter<DistanceChoiceModel>((c, p) => new DistanceLimitViewHost(c, p), items));
where in this case, the extension method looks like
public static IDisposable BindSpinner<TView, TViewModel, TCommandProp, TSpinnerViewModel>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TCommandProp>> viewModelCommandName,
Expression<Func<TViewModel, int>> viewModelSelectedPropertyName,
Expression<Func<TViewModel, IList<TSpinnerViewModel>>> viewModelSourceItemsName,
Expression<Func<TView, Spinner>> spinnerControl, Func<IList<TSpinnerViewModel>, ISpinnerAdapter> adapterFactory) where TViewModel : RxViewModel
where TCommandProp : ICommand
where TView : class, IViewFor<TViewModel>
where TSpinnerViewModel : class
{
来源:https://stackoverflow.com/questions/47135480/xamarin-android-and-spinner-binding-with-reactiveui