Xamrin Button is not working for mmvm-light Relay Command - xamarin

In my Xamrin forms code i have configured MVVM light
RelayCommand is not hitting even though I have set the property in xaml page for the command.
XAML
<?xml version="1.0" encoding="utf-8"?><ContentPage BackgroundColor="White" xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ContractorActionSolution.CSA.CSAContentPages.Demo">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.iOS>0,20,0,0</OnPlatform.iOS>
</OnPlatform>
</ContentPage.Padding>
<ContentPage.Content>
<StackLayout Padding="10" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Image x:Name="imgLogo" Source="sisystems_logo.jpg" HorizontalOptions="FillAndExpand" VerticalOptions="Start"/>
<StackLayout VerticalOptions="CenterAndExpand" Padding="20" HorizontalOptions="FillAndExpand">
<Label x:Name="lblmsg" TextColor="#F25B63" Text="Error Message"/>
<Entry x:Name="txtUserName" Placeholder="Email"/>
<Entry x:Name="txtPassword" Placeholder="Password" IsPassword="True"/>
<Button Command="{Binding IncrementCommand}" Text="Continue"/>
<Label Text="Can't Login ?" TextColor="#F25B63" HorizontalOptions="Center"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
Code
public partial class Demo : ContentPage
{
DemoViewModel _myViewModel;
public Demo ()
{
InitializeComponent ();
}
protected override void OnAppearing()
{
base.OnAppearing();
BindingContext = App.Locator.DemoVM;
_myViewModel = BindingContext as DemoViewModel;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_myViewModel.CleanUP();
}
}
Model
public class DemoViewModel : BaseViewModel
{
private string _name;
public string Name
{
get { return _name; }
set { Set(() => Name, ref _name, value); }
}
private RelayCommand _incrementCommand;
/// <summary>
/// Gets the IncrementCommand.
/// </summary>
public RelayCommand IncrementCommand
{
get
{
return _incrementCommand ?? (_incrementCommand = new RelayCommand(
() =>
{
}));
}
}
public void CleanUP()
{
Name = string.Empty;
}
}
I have also tried using RelayCommand and RelayAsyncCommand both are not working.
Property bindings are working fine,
I can add binding for entry with a string property, but not able to add RelayCommand with a button.

The problem might be the fact that the handler is empty and optimization actually omits it after compilation. Try to add anything inside, like Debug.WriteLine("Test"); to see if the breakpoint is hit then.

Related

Understanding of data binding in Xamarin forms

I am confused with how Xamarin binding works.
OneWay
Indicates that the binding should only propagate changes from source
(usually the View Model) to target (the BindableObject). This is the
default mode for most BindableProperty values.
So by default, if the values are set in the view model it will be reflected in the xaml pages.
But in the Xamarin default template, below is the code to insert a new item. Page doesn't have any two way binding mode set in the markup.
<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="Christianity.Mobile.Views.NewItemPage"
Title="New Item">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Cancel" Clicked="Cancel_Clicked" />
<ToolbarItem Text="Save" Clicked="Save_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Spacing="20" Padding="15">
<Label Text="Text" FontSize="Medium" />
<Entry Text="{Binding Item.Text}" d:Text="Item name" FontSize="Small" />
<Label Text="Description" FontSize="Medium" />
<Editor Text="{Binding Item.Description}" d:Text="Item description" FontSize="Small" Margin="0" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Here I can see that default values of item are populated when a new page is created and also, edited name and description are available while saving the item.
My question - is two way binding implemented by default without having any binding mode set?
public partial class NewItemPage : ContentPage
{
public Item Item { get; set; }
public NewItemPage()
{
InitializeComponent();
Item = new Item
{
Text = "Item name",
Description = "This is an item description."
};
BindingContext = this;
}
async void Save_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send(this, "AddItem", Item);
await Navigation.PopModalAsync();
}
async void Cancel_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
UPDATE
Here is my code to load data asynchronously
<?xml version="1.0" encoding="utf-8" ?>
<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="Christianity.Mobile.Views.ItemDetailPage"
Title="{Binding Title}">
<StackLayout Spacing="20" Padding="15">
<Label Text="Text:" FontSize="Medium" />
<Label Text="{Binding Item.Title}" d:Text="Item title" FontSize="Small"/>
<Label Text="Description:" FontSize="Medium" />
<Label Text="{Binding Item.Description}" d:Text="Item description" FontSize="Small"/>
</StackLayout>
</ContentPage>
public class ItemDetailViewModel : BaseViewModel
{
public ItemListItemDTO SelectedItem { get; set; }
public ItemDTO Item { get; set; }
public ICommand LoadItemCommand;
public ItemDetailViewModel(IPageService pageService, ItemListItemDTO selectedItem)
{
SelectedItem = selectedItem;
LoadItemCommand = new Command(async () => await LoadItem());
}
public async Task LoadItem()
{
IsBusy = true;
try
{
// Both are not working
Item = await ItemsDataStore.GetItemAsync(SelectedItem.Id);
//await Device.InvokeOnMainThreadAsync(async () =>
//{
// Item = await ItemsDataStore.GetItemAsync(SelectedItem.Id);
//});
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
According to Xamarin.Forms Binding Mode, you can see that most bindable properties have a default binding mode of OneWay but the following properties have a default binding mode of TwoWay:
Date property of DatePicker
Text property of Editor, Entry, SearchBar, and EntryCell
IsRefreshing property of ListView
SelectedItem property of MultiPage
SelectedIndex and SelectedItem properties of Picker
Value property of Slider and Stepper
IsToggled property of Switch
On property of SwitchCell
Time property of TimePicker
These particular properties are defined as TwoWay for a very good reason:
When data bindings are used with the Model-View-ViewModel (MVVM) application architecture, the ViewModel class is the data-binding source, and the View, which consists of views such as Slider, are data-binding targets. MVVM bindings resemble the Reverse Binding sample more than the bindings in the previous samples. It is very likely that you want each view on the page to be initialized with the value of the corresponding property in the ViewModel, but changes in the view should also affect the ViewModel property.
The properties with default binding modes of TwoWay are those properties most likely to be used in MVVM scenarios.
Update:
For example, you get data using Web Api, then loading into ItemDTO Item, please comfirm that you have implement INotifyPropertyChanged interface for ItemDTO class to notify data changed.
public class ItemDTO:ViewModelBase
{
private string _Text;
public string Text
{
get { return _Text; }
set
{
_Text = value;
RaisePropertyChanged("Text");
}
}
private string _Description;
public string Description
{
get
{ return _Description; }
set
{
_Description = value;
RaisePropertyChanged("Description");
}
}
}
The ViewModelBase is the class that implement INotifyPropertyChanged.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Binding IsVisible property to my VIewModel

I have some entry, and on focus of that entry I want to show my cancel button.
Here is the xaml:
<RelativeLayout>
<controls:StandardEntry
x:Name="mainEntry"
BackgroundColor="White"
BorderColor="Gray"
BorderThickness="0"
CornerRadius="15"
Placeholder="Search..."
TextColor="LightGray"
HeightRequest="10"
Padding="35,0"
FontSize="Default"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,Factor=0,Constant=40}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width,Factor=0.7,Constant=0}">
<Entry.Behaviors>
<behavior:EventToCommandBehavior EventName="Focused" Command="{Binding SearchBarFocusedCommand}"/>
<behavior:EventToCommandBehavior EventName="Unfocused" Command="{Binding SearchBarUnfocusedCommand}"/>
</Entry.Behaviors>
</controls:StandardEntry>
<Image
Source="Invest_Search_Icon.png"
VerticalOptions="Center"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,ElementName=mainEntry, Property=X,Factor=1,Constant=10}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=mainEntry, Property=Y,Factor=1,Constant=10}"/>
<Image
Source="Invest_Search_Icon.png"
VerticalOptions="Center"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,ElementName=mainEntry, Property=Width,Factor=1,Constant=-25}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=mainEntry, Property=Y,Factor=1,Constant=10}"/>
<Button
Text="Cancel"
TextColor="Gray"
IsVisible="{Binding CancelButtonIsVisible}"
BackgroundColor="White"
VerticalOptions="Start"
CornerRadius="10"
HeightRequest="40"
Margin="0,0,50,0"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,ElementName=mainEntry, Property=Width,Factor=1,Constant=20}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=mainEntry, Property=Y,Factor=1,Constant=0}"/>
</RelativeLayout>
As you see Imusing EventToCommand Behavior, which is work ok (it enters into my command methods). In my VM:
public class InvestViewModel : BaseViewModel, INotifyPropertyChanged
{
public InvestViewModel()
{
SetDefaultContent();
SearchBarFocusedCommand = new Command(() => OnSearchBarFocused());
}
private void OnSearchBarUnfocused()
{
CancelButtonIsVisible = false;
}
private void OnSearchBarFocused()
{
CancelButtonIsVisible = false;
}
private void SetDefaultContent()
{
CancelButtonIsVisible = true;
}
private bool cancelButtonIsVisible;
public bool CancelButtonIsVisible
{
get => cancelButtonIsVisible;
set
{
cancelButtonIsVisible = value;
RaisePropertyChanged(() => CancelButtonIsVisible);
}
}
public ICommand CancelClickCommand { get; set; }
public ICommand SearchBarFocusedCommand { get; set; }
}
So the flow:
On page loading, first SetDefaultContent() => CancelButtonIsVisible = true;
On Entry focused, hide cancel button OnSearchBarFocused() => CancelButtonIsVisible = false;
Apparently, SetDefaultContent is working.
It doesnt work my focus method, when I focused nothing happens, there is still visible cancel button.
Any suggestions?
Option-1
The simpler option would be to bind IsVisible property on 'Cancel' button to IsFocused property on entry (mainEntry) control using named reference.
<Button Text="Cancel"
IsVisible="{Binding IsFocused, Source={x:Reference mainEntry},
Converter={StaticResource NegateBooleanConverter}}" />
You can implement a converter that will negate the boolean value for you. Alternatively you can use triggers as well.
public class NegateBooleanConverter : IValueConverter
{
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !(bool)value;
}
}
Option-2
Another option is to bind IsFocused with a view-model property.
Create a property with setter in viewmodel
public bool IsEntryFocused
{
set
{
CancelButtonIsVisible = !value;
}
}
and set up the binding in view
<controls:StandardEntry
x:Name="mainEntry"
...
IsFocused="{Binding IsEntryFocused}"

How can I add a disclosure indicator / checkmark to my view cell in Xamarin.Forms Android?

Here's what I have implemented so far for iOS:
using System;
using Xamarin.Forms;
namespace Japanese
{
public class ExtCheckedTextCell: TextCell
{
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
"IsChecked", typeof(bool), typeof(ExtCheckedTextCell),
defaultValue: false);
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
}
}
and my renderer looks like this:
using System;
using System.ComponentModel;
using System.Diagnostics;
using Japanese;
using Japanese.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(ExtCheckedTextCell), typeof(ExtCheckedTextCellRenderer))]
namespace Japanese.iOS
{
public class ExtCheckedTextCellRenderer : TextCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var nativeCell = base.GetCell(item, reusableCell, tv);
if (item is ExtCheckedTextCell formsCell)
{
SetCheckmark(nativeCell, formsCell);
SetTap(nativeCell, formsCell);
}
return nativeCell;
}
protected override void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.HandlePropertyChanged(sender, args);
System.Diagnostics.Debug.WriteLine($"HandlePropertyChanged {args.PropertyName}");
var nativeCell = sender as CellTableViewCell;
if (nativeCell?.Element is ExtCheckedTextCell formsCell)
{
if (args.PropertyName == ExtCheckedTextCell.IsCheckedProperty.PropertyName)
SetCheckmark(nativeCell, formsCell);
}
}
void SetCheckmark(UITableViewCell nativeCell, ExtCheckedTextCell formsCell)
{
if (formsCell.IsChecked)
nativeCell.Accessory = UITableViewCellAccessory.Checkmark;
else
nativeCell.Accessory = UITableViewCellAccessory.None;
}
}
For reference here's the XAML where it is used:
<TableSection>
<local:CheckedTextCell Text="{Binding [6].Name}" IsChecked="{Binding [6].IsSelected}" Tapped="atiSelectValue" />
<local:CheckedTextCell Text="{Binding [7].Name}" IsChecked="{Binding [7].IsSelected}" Tapped="atiSelectValue" />
<local:CheckedTextCell Text="{Binding [8].Name}" IsChecked="{Binding [8].IsSelected}" Tapped="atiSelectValue" />
</TableSection>
Does anyone have any ideas how can I implement this in Android using a custom renderer or if it is even possible to do it?
Here's an example (not mine) of what it looks like in iOS. What I am hoping for is the Android can show a similar tick mark on the right side.
Custom Renderer
You can build a custom renderer in Android (although, I think an easier approach is to create a custom ViewCell):
using System.ComponentModel;
using Android.Content;
using Android.Views;
using Android.Widget;
using Sof;
using Sof.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using AView = Android.Views.View;
[assembly: ExportRenderer(typeof(ExtCheckedTextCell), typeof(ExtCheckedTextCellRenderer))]
namespace Sof.Droid
{
public class ExtCheckedTextCellRenderer : TextCellRenderer
{
public const string CheckedText = "✓";
private TextView Check { get; set; }
protected override AView GetCellCore(Cell item, AView convertView, ViewGroup parent, Context context)
{
var view = base.GetCellCore(item, convertView, parent, context) as BaseCellView;
if (this.Check == null)
{
this.Check = new TextView(context);
this.Check.Gravity = GravityFlags.Center;
using (var lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.MatchParent))
{
view.AddView(this.Check, lp);
}
var paddingRight = context.Resources.GetDimension(Resource.Dimension.abc_list_item_padding_horizontal_material);
view.SetPadding(view.PaddingLeft, view.PaddingTop, (int)paddingRight, view.PaddingBottom);
}
return view;
}
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnCellPropertyChanged(sender, args);
if (args.PropertyName.Equals(ExtCheckedTextCell.IsCheckedProperty.PropertyName) &&
sender is ExtCheckedTextCell extCheckedTextCell && this.Check != null)
{
this.Check.Text = extCheckedTextCell.IsChecked ? CheckedText : string.Empty;
}
}
}
}
Custom Xamarin.Forms.ViewCell (no platform-specific code needed)
For a simple layout like you want (label and checkmark), a custom ViewCell seems more appropriate and allows direct control over the style.
ExtCheckedTextCell2.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Sof.ExtCheckedTextCell2"
x:Name="this">
<ViewCell.View>
<StackLayout Orientation="Horizontal"
Padding="12, 0">
<Label HorizontalOptions="FillAndExpand"
Text="{Binding Text, Source={x:Reference this}}"
VerticalTextAlignment="Center" />
<Label IsVisible="{Binding IsChecked, Source={x:Reference this}}"
HorizontalOptions="End"
Text="✓"
VerticalTextAlignment="Center"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
ExtCheckedTextCell2.xaml.cs
public partial class ExtCheckedTextCell2 : ViewCell
{
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
nameof(IsChecked),
typeof(bool),
typeof(ExtCheckedTextCell2),
default(bool));
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(ExtCheckedTextCell2),
default(string));
public ExtCheckedTextCell2()
{
InitializeComponent();
}
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
protected override void OnTapped()
{
base.OnTapped();
this.IsChecked = !this.IsChecked;
}
}
Result
<TableView>
<TableSection Title="Custom Renderer">
<local:ExtCheckedTextCell Text="Test1" Tapped="Handle_Tapped" />
<local:ExtCheckedTextCell Text="Test2" Tapped="Handle_Tapped" />
<local:ExtCheckedTextCell Text="Test3" Tapped="Handle_Tapped" />
</TableSection>
<TableSection Title="Custom Xamarin.Forms ViewCell">
<local:ExtCheckedTextCell2 Text="Test1" />
<local:ExtCheckedTextCell2 Text="Test2" />
<local:ExtCheckedTextCell2 Text="Test3" />
</TableSection>
</TableView>
But you can also do it in xaml ?
This is a xaml only solution :) should work for Android and Ios .
.xaml
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StackoverflowQ.Views.MainPage"
Title="Driving & Navigation">
<ContentPage.Resources>
</ContentPage.Resources>
<ScrollView>
<StackLayout>
<StackLayout x:Name="Header" BackgroundColor="#efeff4" HorizontalOptions="FillAndExpand" HeightRequest="30" Padding="10">
<Label Text="NAVIGATION VOICE VOLUME" Margin="0, 0, 0, 5" VerticalOptions="EndAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal" Padding="10">
<Label Text="No Voice" TextColor="Black" />
<Image Source="checkboxchecker.png" IsVisible="{Binding IsCheckBoxVisible}" HorizontalOptions="EndAndExpand" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCheckBoxCommand}" NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
</StackLayout>
<BoxView HeightRequest="1" HorizontalOptions="FillAndExpand" BackgroundColor="#efeff4" />
</StackLayout>
</ScrollView>
</ContentPage>
ViewModel
namespace StackoverflowQ.ViewModels
{
public class MainPageViewModel : ViewModelBase
{
public DelegateCommand TapCheckBoxCommand { get; set; }
private bool _isCheckBoxVisible;
public bool IsCheckBoxVisible
{
get => _isCheckBoxVisible;
set => SetProperty(ref _isCheckBoxVisible, value);
}
public MainPageViewModel(INavigationService navigationService)
: base(navigationService)
{
Title = "Main Page";
TapCheckBoxCommand = new DelegateCommand(TapCheckBoxSelected);
}
public void TapCheckBoxSelected()
{
IsCheckBoxVisible = !IsCheckBoxVisible;
}
}
}

<ListView> of images - How open URL via TapGestureRecognizer?

How can we open a URL (via TapGestureRecognizer) that is bound to a of images?
My ListView's ItemsSource is _partners (type of List).
The Partner class has two properties - WebUrl and ImageUrl.
<ListView x:Name="partnersListView">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ImageCell ImageSource="{Binding ImageUrl}" Text="{Binding WebUrl}" />-->
<ViewCell>
<Image Source="{Binding ImageUrl}">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Image_TapGestureRecognizer_Tapped" NumberOfTapsRequired="1" CommandParameter="{Binding .}" />
</Image.GestureRecognizers>
</Image>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The list is showing images only, and I would like the app to navigate to a web site when the user taps the image. However, the following code - unsurprisingly - doesn't work.
private void Image_TapGestureRecognizer_Tapped(object sender, System.EventArgs e)
{
var tappedMenuItem = sender as MenuItem;
var partner = tappedMenuItem.CommandParameter as Partner;
Device.OpenUri(new Uri(partner.WebUrl));
}
Any suggestions, please?
Please note:
I want to keep the TapGestureRecognizer in XAML - not in the code-behind.
Thank you.
Best way to tackle this problem, is to bind the SelectedItem of the ListView to a property on your page.
So in your View
<ListView SelectedItem="{Binding SelectedPartner}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Image Source="{Binding ImageUrl}" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
And in the Code Behind
public Partner SelectedPartner
{
set
{
if (value != null)
Device.OpenUri(new System.Uri(value.WebUrl));
}
}
The list is showing images only, and I would like the app to navigate to a web site when the user taps the image. However, the following code - unsurprisingly - doesn't work.
CommandParameter is just for Command, you can't get it from a tap event handler. To accomplish your requirement, you can either use TappedCallback together with TappedCallbackParameter or use Command together with CommandParameter:
Method 1(TapppedCallback and TappedCallbackParameter):
Modify your Partner class to hold an Action<View,object>:
public class Partner
{
public Partner(string weburl, string imageurl)
{
this.WebUrl = weburl;
this.ImageUrl = imageurl;
}
public Partner(string weburl, string imageurl, Action<View, object> callback) : this(weburl, imageurl)
{
this.CallBack = callback;
}
public Action<View, object> CallBack { get; set; }
public string WebUrl { get; set; }
public string ImageUrl { get; set; }
}
In your code-behind, define a TappedCallback function like below and initialize the items source with the this function:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
List<Partner> list = new List<Partner>
{
new Partner("http://www.url.com","timg.jpg",TappedCallback),
new Partner("http://www.url.com","timg.jpg",TappedCallback),
new Partner("http://www.url.com","timg.jpg",TappedCallback),
new Partner("http://www.url.com","timg.jpg",TappedCallback),
new Partner("http://www.url.com","timg.jpg",TappedCallback),
new Partner("http://www.url.com","timg.jpg",TappedCallback)
};
partnersListView.ItemsSource = list;
}
private void TappedCallback(View sender,object param)
{
var Partner = param as Partner;
Device.OpenUri(new Uri(Partner.WebUrl));
}
}
Use TappedCallback in Xaml:
<ListView x:Name="partnersListView">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ImageCell ImageSource="{Binding ImageUrl}" Text="{Binding WebUrl}" />-->
<ViewCell>
<Image Source="{Binding ImageUrl}">
<Image.GestureRecognizers>
<TapGestureRecognizer TappedCallback="{Binding CallBack}" TappedCallbackParameter="{Binding .}" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Method 2(Command and CommandParameter):
Define an ICommand in your Partner class and constructor to accept ICommand:
public class Partner
{
public Partner(string weburl, string imageurl)
{
this.WebUrl = weburl;
this.ImageUrl = imageurl;
}
public Partner(string weburl, string imageurl, ICommand command) : this(weburl, imageurl)
{
this.TapCommand = command;
}
public string WebUrl { get; set; }
public string ImageUrl { get; set; }
public ICommand TapCommand { get; set; }
}
Create a MyCommand class to implement the ICommand interface :
public class MyCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var Partner = parameter as Partner;
Device.OpenUri(new Uri(Partner.WebUrl));
}
}
In your code-behind initialize your items source with a new MyCommand object:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
List<Partner> list = new List<Partner>
{
new Partner("http://www.url.com","timg.jpg",new MyCommand()),
new Partner("http://www.url.com","timg.jpg",new MyCommand()),
new Partner("http://www.url.com","timg.jpg",new MyCommand()),
new Partner("http://www.url.com","timg.jpg",new MyCommand()),
new Partner("http://www.url.com","timg.jpg",new MyCommand()),
new Partner("http://www.url.com","timg.jpg",new MyCommand())
};
partnersListView.ItemsSource = list;
}
}
Use Command in Xaml:
<ListView x:Name="partnersListView">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ImageCell ImageSource="{Binding ImageUrl}" Text="{Binding WebUrl}" />-->
<ViewCell>
<Image Source="{Binding ImageUrl}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" CommandParameter="{Binding .}" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Xamarin Forms + Mvvmcross binding command not work

I am an new Xamarin Form. I created a simple xamarin forms project with mvvmcross (Hello World very simple for begin), but when i implemented binding command, and not effect change text of label. My Xaml code and ViewModel below.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MvvmCross.ViewModels;assembly=MvvmCross"
x:Class="MvvmCross.Views.HelloView">
<StackLayout>
<StackLayout.BindingContext>
<vm:HelloViewModel />
</StackLayout.BindingContext>
<Entry HorizontalOptions="Fill" VerticalOptions="Center" Text="{Binding Name, Mode=TwoWay }"/>
<Button Text="Hello" HorizontalOptions="Center" VerticalOptions="Center" Command="{Binding HelloCommand}" />
<Label HorizontalOptions="Fill" VerticalOptions="Center" FontSize="15" Text="{Binding Hello, Mode=TwoWay}" />
</StackLayout>
using MvvmCross.Core.ViewModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MvvmCross.ViewModels
{
public class HelloViewModel: Core.ViewModels.MvxViewModel
{
private string _name;
public HelloViewModel()
{
Hello = "Your name";
}
public string Name
{
get { return _name; }
set { _name = value; RaisePropertyChanged(() => Name); }
}
private string _hello;
public string Hello
{
get { return _hello; }
set { _hello = value; RaisePropertyChanged(() => Hello); }
}
private ICommand _helloCommand;
public ICommand HelloCommand
{
get { _helloCommand = _helloCommand ?? new MvxCommand(ShowHello); return _helloCommand; }
}
private void ShowHello()
{
// not change label text so sadly
Hello = Name.ToString();
Debug.WriteLine(Hello);
}
}
}
Thank for all helping
Even if late, it could help someone else.
if you have set up correctly MvvmCross on your Xamarin Forms project (review [Getting Started with MvvmCross][1]) you don't need to specifically set the BindigContext, neither in the view nor in the view model.
About the question, simple example of the use of the button's command binding:
view
<views:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr- namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
x:Class="TestProject.Pages.TestPage">
<ContentView>
<StackLayout>
<Button Text="Test first command!" Command="{Binding TestFirstCommand}"/>
<Button Text="Test second command!" Command="{Binding TestSecondCommand}"/>
<Label Text="{Binding AnyText}"/>
</StackLayout>
</ContentView>
view model
namespace TestProject.ViewModels
{
public class TestViewModel : MvxNavigationViewModel
{
private string _AnyTest;
public TestViewModel()
{
AnyText = "";
}
public string AnyText { get => _AnyTest; set => SetProperty(ref _AnyTest, value); }
public Command TestFirstCommand => new Command(TestFirstCommandMethod);
public Command TestSecondCommand => new Command(TestSecondCommandMethod);
private void TestFirstCommandMethod()
{
AnyText = "Hello!";
}
private void TestSecondCommandMethod()
{
AnyText = "How are you?";
}
}
}
Has u set the BindingContext?
In your HelloView.xaml.cs:
public HelloView() {
BindingContext = new HelloViewModel();
}
I'm on mobile, really hard to type..

Resources