Xamarin reuse viewmodel on user control - xamarin

In my MainPage.xaml, which is a ContentPage, I have two user controls.
Both of which are ContentView and are loaded like this:
<local:MyView2 HorizontalOptions="Start"
VerticalOptions="Fill">
<local:MyView2.BindingContext>
<viewmodels:NavbarViewModel />
</local:MyView2.BindingContext>
<local:MyView2.Triggers>
<DataTrigger TargetType="{x:Type local:MyView2}" Binding="{Binding IsPresented}" Value="True">
<DataTrigger.EnterActions>
<local:MenuTrigger IsPresented="True"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<local:MenuTrigger IsPresented="False" />
</DataTrigger.ExitActions>
</DataTrigger>
</local:MyView2.Triggers>
</local:MyView2>
// omitted myview1, they are basically the same
My MainPage has a different viewmodel than MyView1 and 2 which are the contentviews.
But the bindingcontext I have said is not accessible from inside the contentview:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Universal_ONE.MyView1"
x:Name="MyView1Name">
<Frame BackgroundColor="#385C6C"
Padding="0,0,0,0">
<ImageButton Source="outline_menu_white_24.png"
Command="{Binding Source={x:Reference MyView1Name}, Path=PresentMenu}}"
WidthRequest="24"
HeightRequest="24"
Margin="15,0,0,0"
BackgroundColor="Transparent"
HorizontalOptions="StartAndExpand" />
</Frame>
</ContentView>
I also tried it like this:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Universal_ONE.MyView1">
<Frame BackgroundColor="#385C6C"
Padding="0,0,0,0">
<ImageButton Source="outline_menu_white_24.png"
Command="{Binding PresentMenu}"
WidthRequest="24"
HeightRequest="24"
Margin="15,0,0,0"
BackgroundColor="Transparent"
HorizontalOptions="StartAndExpand" />
</Frame>
</ContentView>
The error I get on the PresentMenu: No DataContext found for binding PresentMenu
How do I access the bindingcontext inside my contentview?
If it was not clear already, the contentviews are in a seperate file.
EDIT:
NavbarViewModel:
public class NavbarViewModel : INotifyPropertyChanged
{
public NavbarViewModel()
{
isPresented = false;
PresentMenu = new Command(() => IsPresented = !IsPresented);
}
bool isPresented;
public bool IsPresented
{
get => isPresented;
set
{
isPresented = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsPresented)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand PresentMenu { private set; get; }
}
EDIT 2:
I have added:
x:DataType="viewmodels:NavbarViewModel
To both contentviews, this removes the error that it has no DataContext. However, the binding still does not work.
Working solution:
I have now added the viewmodel as a staticresource in app.xaml and just reuse that everywhere including in the user controls. I hope to look at this again at some point in the future.

Related

Xamarin.Forms GestureRecognizers not working on Command

Code in the xaml page:
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<CollectionView ItemsSource="{Binding MeniElementi}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame Padding="10" WidthRequest="140" HeightRequest="140">
<Frame BackgroundColor="AliceBlue" WidthRequest="120" HeightRequest="120" HasShadow="True" CornerRadius="10" Padding="10" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" >
<StackLayout>
<Image Source="http://www.clker.com/cliparts/l/u/5/P/D/A/arrow-50x50-md.png" WidthRequest="70" HeightRequest="70" >
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding LoadElements}"
/>
</Image.GestureRecognizers>
</Image>
<Label Text="{Binding Title}" HeightRequest="50" WidthRequest="100" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" />
</StackLayout>
</Frame>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
Code in xaml.cs:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Menu: ContentPage
{
MenuViewModel viewModel = new MenuViewModel();
public Menu()
{
InitializeComponent();
BindingContext = viewModel;
}
}
Code in viewmodel.cs
public class MenuViewModel :BaseViewModel, INotifyPropertyChanged
{
public Command LoadElements { get; set; }
public ObservableCollection<Meni> MeniElementi { get; set; }
public MenuViewModel()
{
LoadElements= new Command(execute: async () => await ExecuteElements());
MeniElementi = new ObservableCollection<Meni>() {
new Meni(){Title="Transatcions" ,Picture="xxx"},
new Meni(){Title="Transatcions" ,Picture="xxx"},
};
}
async Task ExecuteElements()
{
try
{
await Application.Current.MainPage.Navigation.PushAsync(new InfoPage());
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
}
}
LoadElements Command not fired. Loading starting menu , showing menu elements just command not working to navigate to another page. Using Xamarin.Forms.Command. On other pages working normal with Command
You could reset the binding path of the tap . So that you can handle the logic in the same command .
in the ContentPage (which contains the CollectionView)
<?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:Name="Page" //set the name of page
x:Class="xxx.xxxPage">
<TapGestureRecognizer Command="{Binding Source={x:Reference Page},Path=BindingContext.LoadElements}"
you need to call the command on the ViewModel of the Page for that you need to do this:-
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LoadElements, Source={x:Reference Name=ThisPage}}" />
</Image.GestureRecognizers>
And put x:Name="ThisPage" in the ContentPage tag of the xaml at the top of the page.
Let me know if you face difficulties.

СarouselView does not display content

СarouselView does not display content. I have the following code in the AppShell.axml
for the whole day I can’t figure out how to make this work. Help make a working code.
<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"
xmlns:local="clr-namespace:test.Views"
BackgroundColor="Azure"
x:Class="test.AppShell">
<CarouselView HorizontalOptions="Center" NumberOfSideItems="1">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="20"
HeightRequest="300"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="11111111111"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</ContentPage>
I have the following code in the AppShell.axml.cs
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace test
{
public partial class AppShell : ContentPage
{
public AppShell()
{
InitializeComponent();
}
}
}
I tried such an example and it works, but I need the option to work from above.
<CarouselView>
<CarouselView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</CarouselView.ItemsSource>
</CarouselView>
Firstly why you place a carsouselView in the Appshell.xaml? I think the AppShell.Xaml is only to set the App configurations.
you can write code in the AppShell.xaml to layout the App menu or flylayout.
if you do not specify a ItemsSource to CarouselView It will not renderer.
you can make the ItemsSource by BindingContext.
Do you want to achieve the result like following GIF?
If so, you could show the content in the CarouselView by DataBinding.
Step 1: Create a Model for your CarouselView, I create it like following code.
public class MyModel
{
public string Name { get; set; }
}
Step 2: create a viewModel for your CarouselView(we can add the content that we want them to display).
public class MyModelView: BaseViewModel
{
public ObservableCollection<MyModel> MyModels { get; set; }
public MyModelView()
{
MyModels = new ObservableCollection<MyModel>();
MyModels.Add(new MyModel() { Name="test1"});
MyModels.Add(new MyModel() { Name = "test2" });
MyModels.Add(new MyModel() { Name = "test3" });
MyModels.Add(new MyModel() { Name = "test4" });
MyModels.Add(new MyModel() { Name = "test5" });
MyModels.Add(new MyModel() { Name = "test6" });
}
}
Step 3: please add the ItemsSource for your CarouselView and binding the properties for xamarin forms control(Label)
<CarouselView HorizontalOptions="Center" NumberOfSideItems="1" ItemsSource="{ Binding MyModels}">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="20"
HeightRequest="300"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Step 4: backend code for your CarouselView.To bind your ModelView for layout.
BindingContext = new MyModelView();
Here is an example project. you can refer to it.
https://github.com/851265601/MyShellCarouselView

Expandable ListView with different child items in Xamarin forms

any suggestions for how to implement expandable list view with different child views in Xamarin forms. Can anyone please help me for this?
To use different template for different cells you want to use DataTemplateSelector, it's documented here: Creating a Xamarin.Forms DataTemplateSelector
First define it in separate class:
public class PersonDataTemplateSelector : DataTemplateSelector
{
public DataTemplate ValidTemplate { get; set; }
public DataTemplate InvalidTemplate { get; set; }
protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
{
return ((Person)item).DateOfBirth.Year >= 1980 ? ValidTemplate : InvalidTemplate;
}
}
Then add it to your page's resources:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Selector;assembly=Selector" x:Class="Selector.HomePage">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="validPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="invalidPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
ValidTemplate="{StaticResource validPersonTemplate}"
InvalidTemplate="{StaticResource invalidPersonTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
And then just use it in your list:
<ListView x:Name="listView" ItemTemplate="{StaticResource personDataTemplateSelector}" />
To have a possibility to expand/hide the cells, you need to:
add a property IsExpanded to the ViewModel of specific list item
change it to true/false on the ItemSelected event of your list
bind the visibility of the view you want to hide/expand to the value of IsExpanded
XAML
<ListView ItemsSource="{Binding YOUR_SOURCE}" SeparatorVisibility="Default"
HasUnevenRows="True" ItemSelected="MyList_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame>
<StackLayout>
<Label Text="My Heading"/>
</StackLayout>
<StackLayout x:Name="moreItemStack" Orientation="Horizontal"
IsVisible="false">
<Label Text="child 1"/>
<Label Text="child 2"/>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView>
C#
private void MyList_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var myItem = e.SelectedItem;
moreItemStack.IsVisible = true;
}
#user3932639 There you go
NOTE: This was written for clarification, it has been tested.

Xamarin Get ListItem Context

I've got a user control that I'm including in a ListView and I want to add dynamic content when the user control initialises based on the listitem binding. I'm not sure how to do this. See the "HOW DO I BIND THIS???"... I presume I should binding my PropertyBinding to the listitem somehow?
Here's my original view with my listview
<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:EngineerApp" x:Class="EngineerApp.GigsPage" NavigationPage.HasNavigationBar="false" xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms">
<ContentPage Title="Gigs" Icon="icon.png">
<StackLayout Orientation="Vertical">
<local:HeaderBar LeftButtonText="Back" RightButtonText="Leave" LeftButtonClickEvent="Back" RightButtonClickEvent="Back"></local:HeaderBar>
<local:ButtonBar LeftButtonText="Add Gig" RightButtonText="Month View" LeftButtonClickEvent="AddGig" RightButtonClickEvent="Back"></local:ButtonBar>
<ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}"></ActivityIndicator>
<ListView HasUnevenRows="true" SeparatorVisibility="Default" ItemsSource="{Binding gigs}" ItemSelected="Handle_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame Padding="20,20,20,20">
<Frame.Content>
<Frame Padding="15,15,15,15" OutlineColor="Gray" BackgroundColor="White">
<Frame.Content>
<StackLayout Padding="20,0,0,0" Orientation="Vertical" HorizontalOptions="CenterAndExpand">
<Label Text="{Binding venue}"
HorizontalTextAlignment="Center"
TextColor="#69add1"/>
<Label Text="{Binding date}"
HorizontalTextAlignment="Center"
FontFamily="OpenSans-Light"
FontSize="9"
TextColor="#69add1"/>
<local:AuthorisationBar SelectedGig="{Binding .}"></local:AuthorisationBar>
</StackLayout>
</Frame.Content>
</Frame>
</Frame.Content>
</Frame>
</ViewCell>
<local:GigCard />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</TabbedPage>
And then here's the user control xaml.
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EngineerApp.AuthorisationBar">
<ContentView.Content>
<StackLayout BackgroundColor="Red" HeightRequest="50" x:Name="barcontent" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label HorizontalOptions="FillAndExpand" VerticalOptions="Center" Text="I want to show some data here once the bindings are working"></Label>
</StackLayout>
</ContentView.Content>
</ContentView>
And here's the code behind for the user control
using System;
using System.Collections.Generic;
using EngineerApp.ViewModels;
using Xamarin.Forms;
namespace EngineerApp
{
public partial class AuthorisationBar : ContentView
{
public static readonly BindableProperty GigProperty = BindableProperty.Create("SelectedGig", typeof(GigViewModel), typeof(AuthorisationBar), new GigViewModel());
public GigViewModel SelectedGig
{
get
{
return (GigViewModel)GetValue(GigProperty);
}
set
{
SetValue(GigProperty, value);
}
}
public AuthorisationBar()
{
InitializeComponent();
BindingContext = this;
}
}
}
UPDATE 1 - Updated all pages to reflect most recent suggestion. With the {Binding .} I now get the error stated below:
"Cannot assign property "SelectedGig": Property does not exists, or is not assignable, or mismatching type between value and property"
Try this:
<local:AuthorisationBar SelectedGig="{Binding .}"></local:AuthorisationBar>
where "." will be the "current" item of the list.
Notice I used SelectedGid in my code as this is the name of the property you defined your custom control, not SelectedGigId.
Also you need to remove this line from the constructor of your custom control:
BindingContext = SelectedGig;
The BindingContext will already be of type GigViewModel
Hope this helps!
UPDATE
Your Custom Control code behind should look:
public partial class AuthorisationBar : ContentView
{
public AuthorisationBar()
{
InitializeComponent();
}
public static readonly BindableProperty SelectedGigProperty = BindableProperty.Create(nameof(SelectedGig), typeof(GigViewModel), typeof(AuthorisationBar), null);
public GigViewModel SelectedGig
{
get
{
return (GigViewModel)GetValue(SelectedGigProperty);
}
set
{
SetValue(SelectedGigProperty, value);
}
}
}
As previously stated you don't need to set anything to the BindingContext
UPDATE 2
In response to your question. The error was that the BindableProperty of your custom control was not complying with the naming conventions requirements.
From Xamarin BindableProperty documentation:
The naming convention for bindable properties is that the bindable property identifier must match the property name specified in the Create method, with "Property" appended to it.
This is why updating your BindableProperty from GigProperty to SelectedGigProperty fixed your issue.
I've done something similar for my current project - passing the current item's ID to my ViewModel (from the code you've posted, it seems you're not using proper separation of concerns under the MVVM paradigm - the VM shouldn't be initialising anything in your view):
<Button Text="Reconnect" Command="{Binding Path=BindingContext.ReconnectCommand, Source={x:Reference Name=ServicesList}}" CommandParameter="{Binding}" VerticalOptions="Center"/>
For reference, the button which is passing the command is embedded in a ListView.DataTemplate, and is passing the ID of the list item it's part of

Xamarin Forms Switch Toggled event doesn't bind with viewmodel

I have a Forms XAML Page and in there I have a listview, and each element has a Switch (xamarin default). I can bind the data from the items to the listview, but I cannot subscrive the Switch event "Toggled", as it causes the item not to show. I also tried with ICommand and Command, as it is instructed to do with buttons, but the result is the same, nothing shown. How can I handle the switch toggle from the my viewmodel?
View
<?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="TouristicWallet.Views.WalletManagementPage"
xmlns:vm="clr-namespace:TouristicWallet.ViewModels"
xmlns:converters="clr-namespace:TouristicWallet.Converters"
>
<ContentPage.BindingContext>
<vm:WalletManagementViewModel x:Name="ViewModel"/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converters:CurrencyIdToCodeConverter x:Key="idToCodeConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="MyCurrencies" ItemsSource="{Binding Currencies, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Currency.Initials, Mode=OneWay}" />
<Switch IsToggled="{Binding IsOwned, Mode=TwoWay}"
Toggled="{Binding Toggled}"
/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
ViewModel
public class WalletManagementViewModel : ViewModelBase
{
private readonly List<OwnedCurrencyWrapper> _currencies = new List<OwnedCurrencyWrapper>();
public List<OwnedCurrencyWrapper> Currencies { get { return _currencies; } }
public WalletManagementViewModel()
{
CurrencyDataAccess cda = new CurrencyDataAccess();
foreach (var item in cda.GetCurrencies())
{
Currencies.Add(new OwnedCurrencyWrapper(item));
}
OnPropertyChanged(nameof(Currencies));
}
public class OwnedCurrencyWrapper
{
public Currency Currency { get; private set; }
public Boolean IsOwned { get; set; }
public ICommand Toggled { get; set; }
public OwnedCurrencyWrapper(Currency currency)
{
Currency = currency;
WalletDataAccess wda = WalletDataAccess.Instance;
IsOwned = wda.IsOwned(Currency.Id);
Toggled = new Command(() => Update());
}
public void Update()
{
WalletDataAccess wda = WalletDataAccess.Instance;
if (IsOwned) wda.RemoveOwnedCurrency(Currency.Id);
else wda.OwnCurrency(Currency.Id);
}
public void Toggled_handler(object sender, ToggledEventArgs e)
{
Update();
}
}
}
I am not using any mvvm framework
First off a Switch can not bind to a Command. See:
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/#Commanding_with_ViewModels
From the above, the Forms controls that can bind to an ICommand are:
Button
MenuItem
ToolbarItem
SearchBar
TextCell (and hence also
ImageCell )
ListView
TapGestureRecognizer
you can just do the following to run code in the View's code behind file, do this in the XAML:
<Switch IsToggled="{Binding IsOwned, Mode=TwoWay}"
Toggled="Handle_Toggled" />
And then in the Code behind file:
void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
{
// Do stuff
}
Alternately, since you are binding, you could run code in the actual OwnedCurrencyWrapper class (which is what you seem to want) just by adding code to the setter for IsOwned. IN this case, don't assign anything to the Toggled property of your switch::
<Switch IsToggled="{Binding IsOwned, Mode=TwoWay}" />
And then in your OwnedCurrencyWrapper class:
bool _isOwned;
public bool IsOwned {
get
{
return _isOwned;
}
set
{
_isOwned = value;
// Do any other stuff you want here
}
}
That said, your binding is not complete since your view model is not implementing INotifyPropertyChanged so changes made directly to the view model will not be reflected in the UI. For more info on binding with Forms MVVM, see:
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/
UPDATE: I was not aware of Behaviors in Xamarin Forms. See:
https://github.com/xamarin/xamarin-forms-samples/tree/master/Behaviors/EventToCommandBehavior
In the context of commanding, behaviors are a useful approach for connecting a control to a command. In addition, they can also be used to associate commands with controls that were not designed to interact with commands. This sample demonstrates using a behavior to invoke a command when an event fires.
So this should allow you to bind the Toggled event to a Command.
If you adhere to Prism framework you may easily wire an event to a command. Your xaml will look like in the following example.
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:b="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
x:Class="TouristicWallet.Views.WalletManagementPage">
<ContentPage.Content>
<StackLayout VerticalOptions="CenterAndExpand" Padding="20">
<Switch IsToggled="{Binding IsOwned}" x:Name="IsOwnedSwitch">
<Switch.Behaviors>
<b:EventToCommandBehavior EventName="Toggled" Command="{Binding ToggleIsOwnedCommand}"/>
</Switch.Behaviors>
</Switch>
</StackLayout>
</ContentPage.Content>
</ContentPage>
As others have mentioned, you should bind the Toggled event to an eventHandler behavior which will forward a command. The code below can be used.
<Switch IsToggled="{Binding SwitchEnabled}" x:Name="MySwitch">
<Switch.Behaviors>
<!-- behaviors namespace comes from "Xamarin.Forms Behaviors" nuget -->
<behaviors:EventHandlerBehavior EventName="Toggled">
<behaviors:InvokeCommandAction Command="{Binding ToggleSwitchCommand}" />
</behaviors:EventHandlerBehavior>
</Switch.Behaviors>
</Switch>
Solution : After doing some R&D i found the root cause of this issue,
Error Code in very first post:
<Switch IsToggled="{Binding IsOwned, Mode=TwoWay}"
Toggled="{Binding Toggled}"
/>
Just do Two steps.
Declare event listener function OnToggled in ContentPage class and not into your ViewModel class that you need to bind
In your ContentPage class
void OnToggled(object sender, ToggledEventArgs e){
}
change Toggled="{Binding Toggled}" == to ==> Toggled="OnToggled"
it will fix the issue, Don't know why it don't work for event listener function declared in ViweModel class.
--I hope it will work.
I had the same issue and solved it in a very easy way.
=> Goal: Get items with a switch control in a listview to respond to a command.
<?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="TouristicWallet.Views.WalletManagementPage"
xmlns:vm="clr-namespace:TouristicWallet.ViewModels"
x:Name="pageName"
xmlns:converters="clr-namespace:TouristicWallet.Converters"
>
<ContentPage.BindingContext>
<vm:WalletManagementViewModel x:Name="ViewModel"/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converters:CurrencyIdToCodeConverter x:Key="idToCodeConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="MyCurrencies" ItemsSource="{Binding Currencies, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Currency.Initials, Mode=OneWay}" />
<Switch IsToggled="{Binding Selected}" HorizontalOptions="Start">
<Switch.Behaviors>
<b:EventToCommandBehavior
EventName="Toggled" Command="
{Binding
Path=BindingContext.SendCommand,
Source={x:Reference
Name=pageName}}" />
</Switch.Behaviors>
</Switch>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
In ViewModel
Define your Command /ICommand
public ICommand SendCommand { get; set; }
SendCommand = new Command(() => //do something.....);
Please Take special note of the areas in bold.

Resources