Update custom listviewAdapter - xamarin.android

I wanne add new data to my listviewAdapter, i tried it with clearing all the data before it and notifying that there is now data but it doesn't seem to work. I followed the Solution (stackoverflow) but it doesn't work.
Does anyone have an idea why?
public class ReportsListViewAdapter : BaseAdapter<IMobileReport>, IFilterable
{
internal List<IMobileReport> originalData;
internal List<IMobileReport> reports;
private Context context;
public override IMobileReport this[int position] => reports[position];
public ReportsListViewAdapter(Context context, IEnumerable<IMobileReport> reports)
{
this.reports = reports.OrderBy(report => report.StudyDate).ToList();
this.context = context;
Filter = new ReportsFilter(this);
}
public override int Count => this.reports.Count;
public Filter Filter { get; private set; }
public override long GetItemId(int position)
{
return position;
}
public void updateReportsList(List<MobileReport> newlist)
{
reports.AddRange(newlist);
this.NotifyDataSetChanged();
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
if(row == null)
{
row = LayoutInflater.From(context).Inflate(Resource.Layout.listView_reports_row, null, false);
}
var txtName = row.FindViewById<TextView>(Resource.Id.txtName);
txtName.Text = reports[position].Student.Name;
var txtFirstName = row.FindViewById<TextView>(Resource.Id.txtFirstName);
txtFirstName.Text = reports[position].Student.FirstName;
var txtSource = row.FindViewById<TextView>(Resource.Id.txtSource);
txtSource.Text = reports[position].Source;
var txtCritical = row.FindViewById<TextView>(Resource.Id.txtCritical);
txtSource.Text = reports[position].Critical.ToString();
return row;
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
reports = new List<IMobileReport>();
//Init();
_reportsHubConnector = new ReportsHubConnector();
#pragma warning disable 4014 // We cannot await this task here because the signature of the inherited method is void
Task.Factory.StartNew(async () =>
{
await _reportsHubConnector.StartConnection();
await _reportsHubConnector.SendT();
}, TaskCreationOptions.PreferFairness);
#pragma warning restore 4014
Console.WriteLine("HomeActivity: OnCreate");
SetContentView(Resource.Layout.activity_reports);
SupportActionBar.SetDisplayShowTitleEnabled(false);
SupportActionBar.SetDisplayHomeAsUpEnabled(false);
SupportActionBar.SetDisplayShowHomeEnabled(true);
WireUpElements();
listView = FindViewById<ListView>(Resource.Id.reports);
ReportsListViewAdapter adapter = new ReportsListViewAdapter(this, reports);
listView.Adapter = adapter;
searchView = FindViewById<SearchView>(Resource.Id.searchView1);
searchView.QueryTextChange += this.Filter;
listView.ItemClick += ItemClicked;
criticalButton = FindViewById<LinearLayout>(Resource.Id.AuthenticatorButton);
criticalButton.Click += criticalClicked;
_reportsHubConnector.ReportsRecieved += (reports) =>
{
adapter.updateReportsList(reports);
};
}
When i debug slowly the GetView does get triggered, maybe this is a clue to why its not being called when i don't debug or go over the code quick.
This.RunOnUiThread is never called but update is.
_reportsHubConnector.ReportsRecieved += (tmpReports) =>
{
adapter.updateReportsList(tmpReports);
this.RunOnUiThread(() =>
{
criticalButton.SetBackgroundColor(Android.Graphics.Color.Red);
});
};

i tried it with clearing all the data before it and notifying that there is now data but it doesn't seem to work.
From shared code , not seeing clear method , you can add reports.Clear() to check whether it works .
public void updateReportsList(List<MobileReport> newlist)
{
reports.Clear();
reports.AddRange(newlist);
this.NotifyDataSetChanged();
}
If not works , need to check whehter added newlist is the correct data format.
========================Update========================
In OnCreate method , where _reportsHubConnector.ReportsRecieved call update method modify as follow :
_reportsHubConnector.ReportsRecieved += (tmpReports) =>
{
adapter.updateReportsList(tmpReports);
};
Change reports argument to tmpReports to avoid mixing with the original data reports .
Therefore , there is another common way to update data of adapter as follow :
_reportsHubConnector.ReportsRecieved += (reports) =>
{
List<IMobileReport> tmp = new List<IMobileReport>();
tmp = reports ; // use a tmp list data for updating , not using original list data
adapter.updateReportsList(tmp);
};
============================Update===============================
From my sample project , I find a interesting phenomenon and that maybe the problem.
Here I will share my custom adapter HomeScreenAdapter :
public class HomeScreenAdapter : BaseAdapter<TableItem> {
List<TableItem> items;
Activity context;
public HomeScreenAdapter(Activity context, List<TableItem> items)
: base()
{
this.context = context;
this.items = new List<TableItem>();
this.items.AddRange(items);
//this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override TableItem this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading+" items";
view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId);
return view;
}
public void UpdateListView(List<TableItem> newTableItem)
{
items.Clear();
items.AddRange(newTableItem);
NotifyDataSetChanged();
}
}
You will see in the Constructor of HomeScreenAdapter , I commented this line of code this.items = items; . The reault that it will work:
However , if I use this.items = items; to replace this.items.AddRange(items);, it will update nothing even can not show anything in ListView .
public HomeScreenAdapter(Activity context, List<TableItem> items)
: base()
{
this.context = context;
this.items = new List<TableItem>();
//this.items.AddRange(items);
this.items = items;
}
The effect :
The possible reason :
If the equal sign is used here, the pointer address of the items will change. When the data is updated, it cannot point to the original data source, so the update cannot be successful.
Therefore , here Constructor of your code can modify as follow to check whehter it works :
public ReportsListViewAdapter(Context context, IEnumerable<IMobileReport> reports)
{
//this.reports = reports.OrderBy(report => report.StudyDate).ToList();
this.reports = new List<IMobileReport>();
this.reports.AddRange(reports.OrderBy(report => report.StudyDate).ToList());
this.context = context;
Filter = new ReportsFilter(this);
}
Related : Here is the sample project link .

Related

Filter ListView with SearchView xamarin

I want to filter Listview by Searchview
I use the following Adapter for the filter and it works if I haven't made any new additions to the adapter
When I add a new item to Listview, the search stops completely until I restart the program after adding, modifying or deleting it
full code
adapter class
Do you want to achieve the result like following GIF?
If you want to add the item to the listview, based on your adapter, you should item in the adapter like following code.
public class TableItemAdapter : BaseAdapter<TableItem>, IFilterable
{
public List<TableItem> _originalData;
public List<TableItem> _items;
private readonly Activity _context;
public TableItemAdapter(Activity activity, IEnumerable<TableItem> tableitems)
{
_items = tableitems.ToList();
_context = activity;
Filter = new TableItemFilter(this);
}
//Add data to the `_items`, listview will be updated, if add data in the activity,
//there are two different lists, so listview will not update.
public void AddData(TableItem tableItem)
{
_items.Add(tableItem);
NotifyDataSetChanged();
}
public override TableItem this[int position]
{
get { return _items[position]; }
}
public Filter Filter { get; private set; }
public override int Count
{
get { return _items.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = _items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = convertView ?? _context.LayoutInflater.Inflate(Resource.Layout.TableItem, null);
//view = _context.LayoutInflater.Inflate(Resource.Layout.TableItem, null);
view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;
return view;
}
public override void NotifyDataSetChanged()
{
// this.NotifyDataSetChanged();
base.NotifyDataSetChanged();
}
}
public class TableItemFilter :Filter
{
private readonly TableItemAdapter _adapter;
public TableItemFilter(TableItemAdapter adapter)
{
_adapter = adapter;
}
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
var returnObj = new FilterResults();
var results = new List<TableItem>();
if (_adapter._originalData == null)
_adapter._originalData = _adapter._items;
if (constraint == null) return returnObj;
if (_adapter._originalData != null && _adapter._originalData.Any())
{
results.AddRange(
_adapter._originalData.Where(
item => item.SubHeading.ToLower().Contains(constraint.ToString()) | item.Heading.ToLower().Contains(constraint.ToString())));
}
returnObj.Values = FromArray(results.Select(r => r.ToJavaObject()).ToArray());
returnObj.Count = results.Count;
constraint.Dispose();
return returnObj;
}
protected override void PublishResults(ICharSequence constraint, FilterResults results)
{
using (var values = results.Values)
_adapter._items = values.ToArray<Java.Lang.Object>().Select(r => r.ToNetObject<TableItem>()).ToList();
_adapter.NotifyDataSetChanged();
// Don't do this and see GREF counts rising
constraint.Dispose();
results.Dispose();
}
}
public class JavaHolder : Java.Lang.Object
{
public readonly object Instance;
public JavaHolder(object instance)
{
Instance = instance;
}
}
public static class ObjectExtensions
{
public static TObject ToNetObject<TObject>(this Java.Lang.Object value)
{
if (value == null)
return default(TObject);
if (!(value is JavaHolder))
throw new InvalidOperationException("Unable to convert to .NET object. Only Java.Lang.Object created with .ToJavaObject() can be converted.");
TObject returnVal;
try { returnVal = (TObject)((JavaHolder)value).Instance; }
finally { value.Dispose(); }
return returnVal;
}
public static Java.Lang.Object ToJavaObject<TObject>(this TObject value)
{
if (Equals(value, default(TObject)) && !typeof(TObject).IsValueType)
return null;
var holder = new JavaHolder(value);
return holder;
}
}
}
Then in the activity, you add the data by adapter.
private void Button1_Click(object sender, System.EventArgs e)
{
tableItemAdapter.AddData(new TableItem() { Heading = "test1222", SubHeading = "sub Test" });
}
Here is my demo, you can download it.
https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/XAListViewSearchDemo.zip

MVVMCROSS Ios Binding ShowViewModel

I've got problem with data-binding in mvvmcross after doing the navigation in the model by calling the showviewmodel-method. On the android side it works.
So the Problem is, that the navigation itself is working but I don't get any data from the model.
Navigation in the model:
ShowViewModel<TeamEventDetailsViewModel>(new { eventID = item.ID });
ViewModel which containts the Data:
public class TeamEventDetailsViewModel
: EventDetailsViewModel
{
public TeamEventModel CurrentEvent
{
get { return MyCurrentEvent as TeamEventModel; }
set
{
MyCurrentEvent = value;
RaisePropertyChanged(() => CurrentEvent);
TickerModel.Comments = value.Comments;
RaisePropertyChanged(() => TickerModel);
LineupModel.Team1Players = value.Team1Players;
LineupModel.Team2Players = value.Team2Players;
RaisePropertyChanged(() => LineupModel);
}
}
private EventDetailsLineupViewModel _lineupModel = new EventDetailsLineupViewModel();
public EventDetailsLineupViewModel LineupModel
{
get { return _lineupModel; }
set { _lineupModel = value; RaisePropertyChanged(() => LineupModel); }
}
public TeamEventDetailsViewModel()
{
EventToken = MvxMessenger.Subscribe<EventUpdateMessage>(OnEventUpdateMessage);
}
private void OnEventUpdateMessage(EventUpdateMessage eventUpdate)
{
if (MyCurrentEvent != null && eventUpdate.Event.ID == MyCurrentEvent.ID)
{
var updatedEvent = (TeamEventModel)eventUpdate.Event;
var myEvent = CurrentEvent;
if(updatedEvent.Score!=null)
myEvent.Score = updatedEvent.Score;
if (updatedEvent.Team1Players != null)
myEvent.Team1Players = updatedEvent.Team1Players;
if (updatedEvent.Team2Players != null)
myEvent.Team2Players = updatedEvent.Team2Players;
CurrentEvent = myEvent;
}
}
protected override void Update(EventModel eventdetails)
{
CurrentEvent = (TeamEventModel) eventdetails;
}
private string _teststring = "success";
public string Teststring
{
get { return _teststring; }
set
{
_teststring = value;
RaisePropertyChanged(()=>_teststring);
}
}
}
As you can see at the bottom I implemented a teststring to prove functionality.
Binding in the View:
public class TeamEventDetailsView : MvxViewController
{
public UILabel TestLabel = new UILabel();
public TeamEventDetailsViewModel TeamEventDetailsViewModel
{
get { return (TeamEventDetailsViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
public override void ViewDidLoad()
{
View.AddSubview(TestLabel);
this.CreateBinding(TestLabel).To<TeamEventDetailsViewModel>(vm => vm.Teststring).Apply();
TestLabel.BackgroundColor = UIColor.Orange;
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
TestLabel.Frame=new RectangleF(0,20,View.Frame.Width,80);
}
}
So I repeat, the navigation itself works but the data from model doesn't get shown on the view.
If I create the ViewModel manually in the View then the binding works also, but in my Situation I can't do that because the Data is pulled depending on the generated Data from the ViewModel which calls the navigation-proceed.
Manual ViewModel:
TeamEventDetailsViewModel = new TeamEventDetailsViewModel();
TeamEventDetailsViewModel.Init(9816);
As I can tell I did exactly the same as Stuard does in his Tutorial:
https://www.youtube.com/watch?v=cbdPDZmuHk8
Does anyone has an advice for me?
Thanks.
MvvmCross does the ViewModel create in base.ViewDidLoad() - if you add that call to your ViewDidLoad override then everything should work ok

Create a custom Spinner

I am trying to customize the MvxSpinner to add some additional controls, here is my code:
public class ChamSpinner : LinearLayout
{
public Spinner Spinner{ get; private set; }
public EventHandler<AdapterView.ItemSelectedEventArgs> ItemSelected;
public ChamSpinner (Context context, IAttributeSet attrs) : this (context, attrs, new ChamSpinnerAdapter (context))
{
}
public ChamSpinner (Context context, IAttributeSet attrs, IMvxAdapter adapter) : base (context, attrs)
{
((Activity)Context).LayoutInflater.Inflate (Resource.Layout.ChamSpinnerLayout, this);
Spinner = FindViewById<Spinner> (Resource.Id.ChamSpinnerSpinner);
int itemTemplateId = MvxAttributeHelpers.ReadListItemTemplateId (context, attrs);
int dropDownItemTemplateId = MvxAttributeHelpers.ReadDropDownListItemTemplateId (context, attrs);
adapter.ItemTemplateId = itemTemplateId;
adapter.DropDownItemTemplateId = dropDownItemTemplateId;
Adapter = adapter;
SetupHandleItemSelected ();
}
public new IMvxAdapter Adapter
{
get { return Spinner.Adapter as IMvxAdapter; }
set
{
var existing = Adapter;
if (existing == value)
return;
if (existing != null && value != null)
{
value.ItemsSource = existing.ItemsSource;
value.ItemTemplateId = existing.ItemTemplateId;
}
Spinner.Adapter = value;
}
}
[MvxSetToNullAfterBinding]
public IEnumerable ItemsSource
{
get
{
return Adapter.ItemsSource;
}
set
{
Adapter.ItemsSource = value;
}
}
public int ItemTemplateId
{
get { return Adapter.ItemTemplateId; }
set { Adapter.ItemTemplateId = value; }
}
public int DropDownItemTemplateId
{
get { return Adapter.DropDownItemTemplateId; }
set { Adapter.DropDownItemTemplateId = value; }
}
public ICommand HandleItemSelected { get; set; }
private void SetupHandleItemSelected ()
{
Spinner.ItemSelected += (sender, args) =>
{
var position = args.Position;
HandleSelected (position);
if (ItemSelected != null)
ItemSelected (sender, args);
};
}
protected virtual void HandleSelected (int position)
{
var item = Adapter.GetRawItem (position);
if (this.HandleItemSelected == null
|| item == null
|| !this.HandleItemSelected.CanExecute (item))
return;
this.HandleItemSelected.Execute (item);
}
}
And I am using it like this:
<cross.android.ChamSpinner
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxDropDownItemTemplate="#layout/myspinneritemdropdown"
local:MvxItemTemplate="#layout/myspinneritem"
local:MvxBind="ItemsSource MyItemsSource; SelectedItem MyItem; Mode TwoWay" />
The spinner is always empty, I tried to add a custom binding on ItemsSource property but the result stilll the same.
How can I do to show my items in my spinner?
Thank you in advance.
I think using BindingInflate instead of Inflate should fix it or even points you in the right direction. https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Droid/BindingContext/IMvxAndroidBindingContext.cs
((IMvxBindingContextOwner)Context).BindingInflate(Resource.Layout.ChamSpinnerLayout, this);
I found this error in my log
MvxBind:Error: 32,12 View type not found - cross.android.ChamSpinner
My custom control is in another assembly so I added it to MvvmCross View assemblies is my Setup class like this
protected override IList<Assembly> AndroidViewAssemblies
{
get
{
var assemblies = base.AndroidViewAssemblies;
assemblies.Add(typeof(ChamSpinner).Assembly);
return assemblies;
}
}
Thank you Stuart for your advices and for your great Framework.

MvvmCross iOS UITableView doesn't update on Property Changed

My table view does not update whenever its source property is changed. The code is as follows:
ViewController:
public override void ViewDidLoad()
{
base.ViewDidLoad();
View.BackgroundColor = UIColor.White;
var table = new UITableView(new RectangleF(0, 80, Device.Width, Device.Height - 80));
Add(table);
var source = new MvxStandardTableViewSource(table, "TitleText SessionInfo");
table.Source = source;
var set = this.CreateBindingSet<JoinSessionViewController, JoinSessionViewModel>();
set.Bind(source).To(vm => vm.AvailableServers);
set.Apply();
table.ReloadData();
}
ViewModel:
private readonly INetworkSessionClient _client;
public JoinSessionViewModel(INetworkSessionClient client)
{
_client = client;
_client.ServerFound += ClientOnServerFound;
_client.BeginSearchingForServers();
}
private void ClientOnServerFound(object sender, ServerFoundEventArgs serverFoundEventArgs)
{
if (AvailableServers.Any(s => s.Identifier == serverFoundEventArgs.ServerInfo.Identifier))
return;
AvailableServers.Add(serverFoundEventArgs.ServerInfo);
RaisePropertyChanged(() => AvailableServers);
}
private List<ServerInfo> _availableServers;
public List<ServerInfo> AvailableServers
{
get { return _availableServers; }
set { _availableServers = value; RaisePropertyChanged(() => AvailableServers); }
}
This was a tricky one. The culprit is this line in MvxTableViewSource:
https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxTableViewSource.cs#L56
public virtual IEnumerable ItemsSource
{
get { return _itemsSource; }
set
{
if (_itemsSource == value) // **** This one ****
return;
if (_subscription != null)
{
_subscription.Dispose();
_subscription = null;
}
_itemsSource = value;
var collectionChanged = _itemsSource as INotifyCollectionChanged;
if (collectionChanged != null)
{
_subscription = collectionChanged.WeakSubscribe(CollectionChangedOnCollectionChanged);
}
ReloadTableData();
}
}
Since I was only adding to the list and not setting it to a new list, the setter was early returning and not firing ReloadTableData(). The fix was to use an ObservableCollection (or anything else that implements INotifyCollectionChanged) instead of a List.
private void ClientOnServerFound(object sender, ServerFoundEventArgs serverFoundEventArgs)
{
if (AvailableServers.Any(s => s.Identifier == serverFoundEventArgs.ServerInfo.Identifier))
return;
// CollectionChanged event is not automatically martialed to UI thread
InvokeOnMainThread(() => AvailableServers.Add(serverFoundEventArgs.ServerInfo));
}
private ObservableCollection<ServerInfo> _availableServers;
public ObservableCollection<ServerInfo> AvailableServers
{
get { return _availableServers; }
set { _availableServers = value; RaisePropertyChanged(() => AvailableServers); }
}
Note that because of my particular case, the ServerFound event is being invoked on a separate thread. That means the INotifyCollectionChanged.CollectionChanged event will also be invoked on a separate thread, so the action of adding the server to the list has to be martialed onto the main thread with InvokeOnMainThread() so that the UI will properly update.
It would be nice if CollectionChanged events would automatically be handled on the UI thread, similar to how RaisePropertyChanged() works.

How to bind Command to ios table section header click?

How can I bind Command to recieve taps on sections of my Table? I am using MvxViewController with custom TableSource, but it seems that I cant add bindings to my VM when creating UIView for sections.
Here is my ViewModel:
public class TestViewModel : MvxViewModel
{
private ObservableCollection<string> _sections;
public ObservableCollection<string> Sections
{
get { return _sections; }
set { _sections = value; RaisePropertyChanged(() => Sections); }
}
private MvxCommand _sectionTappedCommand;
public ICommand SectionTappedCommand
{
get
{
_sectionTappedCommand = _sectionTappedCommand ?? new MvxCommand(DoSectionTappedCommand);
return _sectionTappedCommand;
}
}
private void DoSectionTappedCommand()
{
//I want this command somehow to be called when user taps section header
Debug.WriteLine("Section tapped!");
}
}
My view:
[Register("TestView")]
public class OrderView : MvxViewController
{
public override void ViewDidLoad()
{
View = new UIView() { BackgroundColor = UIColor.White };
base.ViewDidLoad();
var table = new UITableView(new RectangleF(0, 20, 320, 660));
Add(table);
var source = new TestTableSource(table);
table.Source = source;
var set = this.CreateBindingSet<OrderView, OrderViewModel>();
// I think here I need to write something like:
// set.Bind(source).For(s => s.Section.TapAction).To(vm => vm.SectionTappedCommand);**
set.Bind(source).For(s => s.ItemsSource).To(vm => vm.Sections).OneWay();
set.Apply();
}
}
Table source:
public class TestTableSource : MvxBaseTableViewSource
{
// all needed overrides implemented
private IList<OrderGuest> _sections;
public IList<OrderGuest> ItemsSource
{
get
{
return _sections;
}
set
{
_sections = value;
ReloadTableData();
}
}
public override UIView GetViewForHeader(UITableView tableView, int section)
{
// Do I need to add bindings here?
var view = new OrderGuestSectionHeader(OrderGuestSectionHeader(tableView, section), () => {
Debug.WriteLine("selected " + section.ToString());
});
return view;
}
public override int NumberOfSections(UITableView tableView)
{
if (_sections == null)
return 0;
return _sections.Count;
}
public override string[] SectionIndexTitles(UITableView tableView)
{
if (_sections == null)
return null;
return _sections.Select(x => x.Name).ToArray();
}
}
Subclassed UIView for section header:
public sealed class OrderGuestSectionHeader : UIView
{
private UIButton SectionButton;
public Action TapAction;
public OrderGuestSectionHeader(string header, Action tapped)
{
Frame = new RectangleF(0, 0, 320, 20);
BackgroundColor = UIColor.Blue;
SectionButton = new UIButton(this.Frame);
SectionButton.TouchUpInside += SectionButton_TouchUpInside;
SectionButton.Title(header);
TapAction = tapped;
Add(SectionButton);
}
private void SectionButton_TouchUpInside(object sender, EventArgs e)
{
TapAction();
}
}
There are a few ways you could achieve this effect.
For just your current requirements, the easiest way to achieve it would be to add just a single command to the TestTableSource and to have that command passed on to your section header inside the Action handler.
public class TestTableSource : MvxBaseTableViewSource
{
public ICommand FooCommand { get; set; }
// existing code
public override UIView GetViewForHeader(UITableView tableView, int section)
{
var view = new OrderGuestSectionHeader(OrderGuestSectionHeader(tableView, section), () => {
Debug.WriteLine("selected " + section.ToString());
if (FooCommand != null) FooCommand.Execute(null);
});
return view;
}
}
This Command can then be bound to the ViewModel by adding the OrderView binding:
set.Bind(source)
.For(s => s.FooCommand)
.To(vm => vm.SectionTappedCommand)
.OneWay();
If you wanted to go further - if you wanted to do a more complicated binding - then you could actually set up a full binding DataContext for the Header View. The easiest way to do this would be to inherit from MvxView. I won't go into the full detail of this here - instead for an introduction to MvxView, see the N+1 video - http://slodge.blogspot.co.uk/2013/06/n32-truth-about-viewmodels-starring.html with sample source code in https://github.com/slodge/NPlus1DaysOfMvvmCross/tree/master/N-32-ViewModels

Resources