MvxItemTemplate ItemClick Binding - xamarin.android

I have the following binding on a MvxListView
<Mvx.MvxListView
android:id="#+id/listGroups"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_below="#+id/layoutGroupPadder"
android:dividerHeight="7dp"
android:divider="#drawable/list_divider"
local:MvxItemTemplate="#layout/list_group"
local:MvxBind="ItemsSource AvailableGroups; ItemClick GroupSelectedCommand" />
The MvxItemTemplate is as follows
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res/xxxx.xxxx"
android:orientation="horizontal"
android:background="#color/white"
android:layout_width="fill_parent"
android:layout_height="63dp">
<TextView
android:id="#+id/groupsGroupName"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="7dp"
android:textColor="#color/verydarknavy"
local:MvxBind="Text Name" />
<RelativeLayout
android:id="#+id/layoutGroupGroupCount"
android:orientation="horizontal"
android:layout_width="90dp"
android:layout_height="fill_parent"
android:layout_centerInParent="true">
<TextView
android:id="#+id/groupsSubGroupCount"
android:layout_width="50dp"
android:layout_height="fill_parent"
android:textSize="16dp"
android:gravity="center"
android:layout_margin="7dp"
android:textColor="#color/hblue"
android:layout_toLeftOf="#+id/imageArrowGrp"
local:MvxBind="Text SubGroupCount" />
<ImageView
android:src="#drawable/YellowArrowRight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="7dp"
android:layout_alignParentRight="true"
android:id="#+id/imageArrowGrp" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/layoutGroupItemCount"
android:orientation="horizontal"
android:layout_width="90dp"
android:layout_height="fill_parent"
android:layout_marginRight="14dp"
android:layout_alignParentRight="true"
android:fitsSystemWindows="false">
<TextView
android:id="#+id/groupsVehicleCount"
android:layout_width="50dp"
android:layout_height="fill_parent"
android:textSize="16dp"
android:gravity="center"
android:layout_margin="7dp"
android:textColor="#color/hblue"
android:layout_toLeftOf="#+id/imageArrowItem"
local:MvxBind="Text VehicleCount" />
<ImageView
android:src="#drawable/YellowArrowRight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_margin="7dp"
android:id="#+id/imageArrowItem" />
</RelativeLayout>
</RelativeLayout>
When the ItemClick happens the GroupSelectedCommand fires correctly :)
However I want to fire 2 different commands depending where within the item the user touches. I need to distinguish which of the TexViews have been touched (SubGroupCount or VehicleCount)
I tried changing the binding in the MvxListView to be
local:MvxBind="ItemsSource AvailableGroups" />
and changed the binding with the MvxItemTemplate to be
local:MvxBind="Text SubGroupCount; ItemClick GroupSelectedCommand " />
and
local:MvxBind="Text VehicleCount; ItemClick ItemSelectedCommand " />
and I created the necessary handling for the command ItemSelectedCommand.
Unfortunately it didn't fire either command.
Is it possible to fire separate commands from one template, and if so how do I bind them to different controls within the MvxItemTemplate?

To accomplish this you need to have two separate commands that are bound to the view inside the row.
Add this to both of the relative layouts that you want to have separate clicks:
local:MvxBind="Click OpenFirstCommand"
Now you need to have access to the viewmodel the list is bound to instead of the Viewmodel of the row itself. There are multiple approaches you can take there to fix that.
Wrap the RowViewmodel into a Wrapper Item. For more detail see this: Binding button click in ListView template MvvMCross
Use a value converter to wrap the Row into a wrapper item. More info on that one: How to binding list item to whether it is contained in another collection
I would personally go for the converter, because it keeps your code more clean. The converter could look like:
public class ListWrapperValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
IEnumerable items = value as IEnumerable;
IList<CellWrapperViewModel<Item>> cellWrapperItems = items.OfType<Item>().Select(x => new CellWrapperViewModel<Item>(x, (BaseViewModel)parameter)).ToList();
ObservableCollection<CellWrapperViewModel<Item>> itemsList = new ObservableCollection<CellWrapperViewModel<Item>> (cellWrapperItems);
// If the old collection was observable, forward the triggers, happening on the old one to the new collection.
if (value as ObservableCollection<Item> != null) {
ObservableCollection<Item> documents = value as ObservableCollection<Item>;
documents.CollectionChanged += (object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) => {
switch (e.Action) {
default:
itemsList.SwitchTo (documents.Select (x => new CellWrapperViewModel<Item> (x, (BaseViewModel)parameter)).ToList ());
break;
}
};
}
return itemsList;
}
}
The Wrapper would be:
public class CellWrapperViewModel<T>
{
public T Item { get; set; }
public BaseViewModel ViewModel { get; set; }
public CellWrapperViewModel(T item, BaseViewModel viewModel)
{
Item = item;
ViewModel = viewModel;
}
}
Your MvxListView binding would then be:
local:MvxBind="ItemsSource ListWrapper(Items, .)"
Your converter for the commands inside the row:
public class OpenFirstCommandValueConverter : MvxValueConverter<CellWrapperViewModel<Item>, MvxCommand>
{
protected override MvxCommand Convert(CellWrapperViewModel<Item> value, Type targetType, object parameter, CultureInfo culture)
{
BaseViewModel viewModel = value.ViewModel;
Item item = value.Item;
return new MvxCommand(() => { viewModel.OptionCommand.Execute((Item)item); });
}
}
If you've done that the binding for the layouts would change to something like this:
local:MvxBind="Click OpenFirstCommand(.)"
local:MvxBind="Click OpenSecondCommand(.)"
More information on this issue is also on the mvvmcross GitHub: https://github.com/MvvmCross/MvvmCross/issues/35

Related

Can I populate a Label within my CollectionView with a value outside the ItemsSource List that populates the view?

I have a Label within my CollectionView that I need to populate with a value outside the ItemsSource List that populates the view.
The following code is an example of what I am trying to accomplish but it seems that the CollectionView is limiting the binding context to just the Items list. I have tried naming the label and setting it in my c# code but I cant seem to access the label in c#. I suppose I could build the whole page in c# rather than using the .xaml but unlike this example my actual code uses multiple templates and a template selector. If I could figure this out without rewriting hours of code I would prefer it.
ItemsPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="TabTest.Views.ItemsPage"
Title="{Binding Title}"
x:Name="BrowseItemsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
</ContentPage.ToolbarItems>
<StackLayout Padding="10">
<Label Text="{Binding TestVal}" FontSize="16" HeightRequest="20" />
<!-- ^^^^ This label displays just as expected -->
<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
<CollectionView x:Name="ItemsCollectionView"
ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Label x:Name="TestV" Text="{Binding Path=BindingContext.TestVal}" />
<!-- ^^^^ I want this Label to display the TestVal string in the ViewModel -->
<Label Text="{Binding Text}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Description}"
d:Text="Item descripton"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="OnItemSelected"></TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</StackLayout>
</ContentPage>
ItemsViewModel.cs
namespace TabTest.ViewModels
{
public class ItemsViewModel : BaseViewModel
{
public ObservableCollection<Item> Items { get; set; }
public Command LoadItemsCommand { get; set; }
private string testVal;
public string TestVal // I want the value of this variable in that Label
{
get
{
return testVal;
}
set
{
testVal = value;
}
}
public ItemsViewModel()
{
Title = "Browse";
TestVal = "Value123";
Items = new ObservableCollection<Item>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
MessagingCenter.Subscribe<NewItemPage, Item>(this, "AddItem", async (obj, item) =>
{
var newItem = item as Item;
Items.Add(newItem);
await DataStore.AddItemAsync(newItem);
});
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Items.Clear();
var items = await DataStore.GetItemsAsync(true);
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
}
I ended up using a dynamic resource in Xaml and used code behind to modify the resource when it needed to change.
Xaml:
<Label x:Name="TestV" Text="{DynamicResource TestValue}" />
Code Behind:
Application.Current.Resources["TestValue"] = NewValue;
App.xaml:
<x:String x:Key="TestValue">Value123</x:String>

Current Location Using Xamarin Android

The problem is i'm trying to get the current location of the user and the code is not giving any error except that when the code compiles, it should execute onLocationChanged method but it does't executes it.
I have also Set the permissions right in my manifest file, but i don't know why i can't seem to understand what the problem is. Please help.
Map Activity
this is my map activity where i'm trying to set the marker to current location
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Graphics;
using Android.Locations;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Newtonsoft.Json;
namespace RoutineApp
{
[Activity(Label = "GoogleMapDirectionsActivity", MainLauncher = true, ScreenOrientation = ScreenOrientation.Portrait, Theme = "#style/Theme.AppCompat.Light.NoActionBar")]
public class GoogleMapDirectionsActivity : Activity, IOnMapReadyCallback, ILocationListener
{
private GoogleMap gMap;
private MapFragment mapFragment;
private LocationManager locationManager;
string locationProvider;
private MarkerOptions markerOptions;
private Marker marker;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.googlemapdirections);
mapFragment = (MapFragment)FragmentManager.FindFragmentById(Resource.Id.DirectionMap);
mapFragment.GetMapAsync(this);
goBtn = FindViewById<Button>(Resource.Id.GoBtn);
//user location
IntializeLocationManager();
}
private void IntializeLocationManager()
{
locationManager = (LocationManager)GetSystemService(LocationService);
Criteria criteriaForLocationService = new Criteria
{
Accuracy = Accuracy.Fine
};
IList<string> acceptableLocationProviders = locationManager.GetProviders(criteriaForLocationService, true);
if (acceptableLocationProviders.Any())
{
locationProvider = acceptableLocationProviders.First();
}
else
{
locationProvider = string.Empty;
}
//Log.Debug(TAG, "Using " + locationProvider + ".");
}
public void OnMapReady(GoogleMap googleMap)
{
gMap = googleMap;
//mDirectionMap.TrafficEnabled = true;
gMap.UiSettings.CompassEnabled = true;
gMap.UiSettings.MyLocationButtonEnabled = true;
gMap.UiSettings.ZoomControlsEnabled = true;
OnLocationChanged(locationManager.GetLastKnownLocation(locationProvider));
}
protected override void OnResume()
{
base.OnResume();
locationManager.RequestLocationUpdates(locationProvider, 400, 0, this);
}
protected override void OnPause()
{
base.OnPause();
locationManager.RemoveUpdates(this);
}
public void OnLocationChanged(Location location)
{
if (marker != null)
{
marker.Remove();
}
LatLng latLng = new LatLng(location.Latitude, location.Longitude);
markerOptions = new MarkerOptions()
.SetPosition(latLng)
.SetTitle("My Current Position");
marker = gMap.AddMarker(markerOptions);
CameraUpdate camera = CameraUpdateFactory.NewLatLngZoom(latLng, 19);
gMap.MoveCamera(camera);
}
public void OnProviderDisabled(string provider)
{
//throw new NotImplementedException();
}
public void OnProviderEnabled(string provider)
{
//throw new NotImplementedException();
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
//throw new NotImplementedException();
}
}
Xml Map activity
xml for my map activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:weightSum="100"
android:background="#android:color/holo_blue_dark">
<EditText
android:id="#+id/SourceTxtBox"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/edit_text_style"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"
android:hint="Enter Starting Point"
android:layout_weight="7"
android:textColorHint="#a3a3a3"
android:textColor="#000" />
<EditText
android:id="#+id/DestinationTxtBox"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/edit_text_style"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"
android:hint="Enter Destination"
android:layout_weight="7"
android:textColorHint="#a3a3a3"
android:textColor="#000" />
<fragment
android:id="#+id/DirectionMap"
android:layout_height="0dp"
android:layout_width="match_parent"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_weight="80" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="6"
android:weightSum="10">
<Button
android:id="#+id/GoBtn"
android:text="Go"
android:textSize="10dp"
android:textStyle="bold"
android:layout_height="wrap_content"
android:layout_width="20dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="com.company.RoutineApp" android:versionCode="1" android:versionName="1">
<uses-sdk android:minSdkVersion="15" />
<!-- Google Maps for Android v2 requires OpenGL ES v2 -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- We need to be able to download map tiles and access Google Play Services-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Allow the application to access Google web-based services. -->
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<!-- Google Maps for Android v2 will cache map tiles on external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must download data -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to receive remote notifications from Google Play Services -->
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
<uses-permission android:name="com.company.RoutineApp.permission.MAPS_RECEIVE" />
<permission android:name="com.company.RoutineApp.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
<!-- These are optional, but recommended. They will allow Maps to use the My Location provider. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>-->
<application android:label="#string/app_name" android:icon="#drawable/Icon" android:theme="#style/Theme.MyTheme">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyAGQlTIquLL5yyIr47pI_AA9g1CI-Whh0o" />
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
</application>
</manifest>
This is the screen shot of my application

Binding issue in custom Xamarin.Forms control

I have a strange problem with bindings on a custom control. I created a custom toolbar:
public partial class TopToolbar
{
public static readonly BindableProperty BackCommandProperty =
BindableProperty.Create(nameof(BackCommand), typeof(ICommand), typeof(TopToolbar), propertyChanged: BackCommandChanged);
public ICommand BackCommand
{
get => (ICommand) GetValue(BackCommandProperty);
set => SetValue(BackCommandProperty, value);
}
public TopToolbar()
{
InitializeComponent();
}
// for debug purposes only
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
Debug.WriteLine(BindingContext);
}
// for debug purposes only
private static void BackCommandChanged(BindableObject bindable, object oldvalue, object newvalue)
{
Debug.WriteLine($"old: {oldvalue}, new: {newvalue}");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Core.Controls.TopToolbar"
x:Name="TopToolbarView"
BindingContext="{x:Reference TopToolbarView}"
Orientation="Vertical">
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
<Image Source="{StaticResource Image.Toolbar.LeftArrow}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BackCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
I use it on a page in this way:
<pages:ContentPage.Content>
<StackLayout BackgroundColor="{StaticResource LightGrayColor}"
Spacing="0"
Padding="0">
<controls:TopToolbar Title="Master Data" BackCommand="{Binding MyBackCommand}" />
BindingContext of the page is a view model:
public class MyCustomersPageModel
{
public RelayCommand MyBackCommand { get; set; }
public MyCustomersPageModel()
{
MyBackCommand = // command creation;
}
}
From the debugging I know that BindingContext of a control is set (OnBindingContextChanged called) properly to itself (TopToolbar object) twice - first time when there's no child views and second time after they are added. I've checked that BindingContext is correctly propagated in all child controls.
Unfortunately the BackCommand is not bind at all. The setter of the TopToolbar.BackCommand is not called even once.
Interestingly when I replace setting the BindingContext on a control to setting the Souce directly in bindings everything works fine:
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Core.Controls.TopToolbar"
x:Name="TopToolbarView"
Orientation="Vertical">
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
<Image Source="{StaticResource Image.Toolbar.LeftArrow}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference TopToolbarView}, Path=BackCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
Any clue what I do wrong?
It is working as expected. I would recommend using Source.
In first case, when you set BindingContext on TopToolbar to itself, then I would imagine this would be the sequence of events:
Custom control is constructed, BindingContext is assigned to self through reference.
Page instance is created, control is added to it.
When page's BindingContext is set, through power of property inheritance, all it's child controls' BindingContext is updated.
At this point your custom control's BindingContext is still referencing itself as value-propagation doesn't override manually set context.
Therefore, binding <controls:TopToolbar BackCommand="{Binding MyBackCommand}" fails, as this binding will try to look for MyBackCommand on it's binding-context which is TopToolbar.
But, in second case, when you specify binding Source as TopToolbar on Tapped command, then this should be the sequence of events:
Custom control is constructed, BindingContext is null.
Page instance is created, control is added to it.
When page's BindingContext is set, through power of property inheritance, all it's child controls' BindingContext is updated, including your custom control.
At this point your custom control's BindingContext is now referencing MyCustomersPageModel. So binding in <controls:TopToolbar BackCommand="{Binding MyBackCommand}" is appropriately set.
Now the Tapped binding doesn't care about BindingContext as it's source is explicitly specified, which is parent control TopToolbar - whose BackCommand in turn is bound to the view model's command. Hence, the view-model command is now bound to gesture-recognizer's Tapped command. And it works!

How to dynamically add listheaders and listcells in ZK

I am totally new in ZK. I need to create N listheaders and N listcells in my zul file. But I do not know how to do it from my java controller and I am not using MVVM.
The problem would be something like:
#Wire
private Window idWindow;
private Listheader header;
private Listcell item1;
#Override
public void onCreate(Event event) {
header.setLabel("laaaa");// It would set just one header but I can have many (N headers) and same for items
}
<zk>
<window id="idWindow" title="nameWindow" apply="controller.java" border="normal" closable="true" sizable="true" maximizable="true" maximized="true" height="85%" width="150%" style="overflow:auto;">
<!-- CONTINUES -->
<listbox id="mainList" hflex="1" vflex="1">
<listhead>
<listheader id="header" label="A" />
<listheader id="header1" label="B" />
<listheader id="header2" label="C" />
....
<listheader id="headerN" label="N" />
</listhead>
<listitem>
<listcell id="item1" label="A"/>
<listcell id="item2" label="B"/>
<listcell id="item3" label="C"/>
....
<listcell id="itemN" label="D"/>
</listitem>
</listbox>
<!-- CONTINUES -->
</window>
</zk>
You can leave the listhead empty in the zul, wire it into your controller and create the listheaders there. The important step is to ask the listbox for its listhead, and append the listheaders to it. For the cells, give your listbox a renderer that creates them for each item if you use a model to give your list data.
Your zul will be much shorter:
<zk>
<window ... >
<listbox id="mainList" hflex="1" vflex="1">
<listhead />
</listbox>
</window>
</zk>
Then in your controller, you create the header in doAfterCompose and attach the renderer:
#Wire
private Listbox mainList;
#Override // This method should be specified by a composer super class
public void doAfterCompose(Component comp)throws Exception
{
super.doAfterCompose(comp);
mainList.setModel(someModelWithYourData);
// create listheaders (manually/in for-loop/based on data...)
Listhead head = mainList.getListhead();
head.appendChild(new Listheader("A"));
...
// attach renderer
mainList.setItemRenderer(new ListitemRenderer<Object>() // use proper data type instead of Object
{
#Override
public void render(Listitem item, Object data, int index)
throws Exception
{
item.appendChild(new Listcell("a"));
...
}
});
}
There is also an example on zk's developer sites: https://www.zkoss.org/wiki/ZK_Developer%27s_Reference/MVC/View/Renderer/Listbox_Renderer
In case you cannot use a model, you could also append the listitems in the zul or in the controller, and then create the listcells:
for (Component child : mainList.getChildren())
{
if (child instanceof Listitem)
{
Listitem item = (Listitem) child;
// do the same as in the renderer
}
}

MvvmCross Bind command to <include> toolbar

I want to bind commands to my toolbars' items. Is it possible?
I have tried this but it's still doesn't work https://stackoverflow.com/a/21936542/6160208
Toolbar.axml
<Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:background="#android:color/holo_blue_light"
android:layout_width="match_parent"
android:layout_height="85dp">
<ImageButton
android:src="#drawable/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/searchImageButton"
android:layout_marginLeft="290dp"
local:MvxBind="Click DoSearchCommand"
android:background="#android:color/holo_blue_light" />
MainView.axml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include
layout="#layout/toolbar" />
</LinearLayout>
MainViewModel.cs
private MvxCommand _searchCommand;
public System.Windows.Input.ICommand SearchCommand
{
get
{
_searchCommand = _searchCommand ?? new MvxCommand(DoSearchCommand);
return _searchCommand;
}
}
private void DoSearchCommand()
{
ShowViewModel<SearchViewModel>();
}
You bind to DoSearchCommand but that is the method. You should bind to SearchCommand
local:MvxBind="Click SearchCommand"
As improvement you could use a IMvxCommand instead of a ICommand too, and add the ShowViewModel as lambda.
private MvxCommand _searchCommand;
public IMvxCommand SearchCommand
{
get
{
_searchCommand = _searchCommand ?? new MvxCommand(() => ShowViewModel<SearchViewModel>());
return _searchCommand;
}
}

Resources