MVVMCross Get SelectedItem from MvxBindableListView

A little problem with my Android app, and I don't know how to solve it using MVVM Cross.

Here is my ViewModel:

public class AddressesShowViewModel : MvxViewModel { public List<Address> Addresses { get; set; } public AddressesShowViewModel(string addressesForListView) { Addresses = JsonConvert.DeserializeObject<List<Address>>(addressesForListView); } public IMvxCommand ShowItemCommand { get { //return new MvxRelayCommand<Type>((type) => this.RequestNavigate(type)); return new MvxRelayCommand(DoShowContact); } } private Address selectedItem; public Address SelectedItem { get { return selectedItem; } set { selectedItem = value; FirePropertyChanged(() => SelectedItem); } } private void DoShowContact() { RequestNavigate<AddressShowViewModel>(); } } 

My AddressesShow.axml

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res/INMobileCRM4Android.INMobileCRM4Android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Mvx.MvxBindableListView android:layout_width="fill_parent" android:layout_height="fill_parent" local:MvxBind="{'ItemsSource':{'Path':'Addresses'},'ItemClick':{'Path':'ShowItemCommand'}, 'SelectedItem':{'Path':'SelectedItem'}}" local:MvxItemTemplate="@layout/addresslistitem" /> </FrameLayout> 

I would like to know how I can get SelectedItem from a ListView in AddressesShow.axml .. I tried to create a Property 'SelectedItem' .. But it is called at the beginning when the ViewModel is created (and obviously returns null), and not when the item is clicked . Its btw is an address type, not just a string or something like that. Maybe some suggestions?

+4
source share
1 answer

The lack of SelectedItem in the Droid was identified as a problem last week while preparing for Daniel's talk in Build.

To get around this, there were a few quick answers:

1 There is a SelectedItemPosition that you can use to bind - this is an int

2 You can use the Click ICommand/IMvxCommand instead of using SelectedItem - in your example, it will be the same axml, but

 public IMvxCommand ShowItemCommand { get { return new MvxRelayCommand<Address>(address => DoShowContact(address)); } } 

To be clear , this Click parameter above is what I will use.


If SelectedItem is really necessary ...

Then for a complete answer, Daniel and I prototyped a new binding. This binding has been reported using:

  registry.RegisterFactory(new MvxCustomBindingFactory<MvxBindableListView>("SelectedItem", adapterView => new MvxAdapterViewSelectedItemTargetBinding(adapterView))); 

and contained the logic:

 using System; using Android.Widget; using Cirrious.MvvmCross.Binding.Droid.Views; using Cirrious.MvvmCross.Binding.Interfaces; using Cirrious.MvvmCross.Interfaces.Platform.Diagnostics; namespace Cirrious.MvvmCross.Binding.Droid.Target { #warning This needs to be redone for all adapterviews not just list view! #warning The use of ItemClick instead of ItemSelected needs to be reinvestigated here! public class MvxAdapterViewSelectedItemTargetBinding : MvxBaseAndroidTargetBinding { private readonly MvxBindableListView _view; private object _currentValue; public MvxAdapterViewSelectedItemTargetBinding(MvxBindableListView view) { _view = view; ((ListView)_view).ItemClick += OnItemClick; } private void OnItemClick(object sender, AdapterView.ItemClickEventArgs itemClickEventArgs) { var container = (_view.GetItemAtPosition(itemClickEventArgs.Position) as MvxJavaContainer); if (container == null) { MvxBindingTrace.Trace(MvxTraceLevel.Warning, "Missing MvxJavaContainer in MvxAdapterViewSelectedItemTargetBinding"); return; } var newValue = container.Object; if (!newValue.Equals(_currentValue)) { _currentValue = newValue; FireValueChanged(newValue); } } public override void SetValue(object value) { #warning Sort out Equals test here if (value != null && value != _currentValue) { var index = _view.Adapter.GetPosition(value); if (index < 0) { MvxBindingTrace.Trace(MvxTraceLevel.Warning, "Value not found for spinner {0}", value.ToString()); return; } _currentValue = value; _view.SetSelection(index); } } public override MvxBindingMode DefaultMode { get { return MvxBindingMode.TwoWay; } } public override Type TargetType { get { return typeof(object); } } protected override void Dispose(bool isDisposing) { if (isDisposing) { ((ListView)_view).ItemClick -= OnItemClick; } base.Dispose(isDisposing); } } } 

To test this, I used the Tutorial PullToRefresh code using:

 <Mvx.MvxBindableListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" local:MvxBind="{'ItemsSource':{'Path':'Emails'},'ItemClick':{'Path':'ShowItemCommand'},'SelectedItem':{'Path':'TheSelectedEmail'}}" local:MvxItemTemplate="@layout/listitem_email" /> 

and

  public class SimpleEmail { public string From { get; set; } public string Header { get; set; } public string Message { get; set; } } private ObservableCollection<SimpleEmail> _emails; public ObservableCollection<SimpleEmail> Emails { get { return _emails; } private set { _emails = value; RaisePropertyChanged(() => Emails); } } private SimpleEmail _email; public SimpleEmail TheSelectedEmail { get { return _email; } set { _email = value; MvxTrace.Trace(MvxTraceLevel.Error, "HELLO {0} ", value == null ? "null" : value.From); } } 

One thing that should be careful in all this work is that the list item selected in Android is slightly different from the selected list item in Silverlight / wp - for example. It can be quite difficult to get the list in android to highlight the current selection, and it can be quite difficult to get listview to generate the highlighted modified events.


Note. I registered the problem in the Droid SelectedItem for https://github.com/slodge/MvvmCross/issues/52 - I will definitely contact the core library in the near future

+3
source

Source: https://habr.com/ru/post/1445486/


All Articles