I have a custom view which will be used across many pages. I have a Close Button in the Custom View where I need to bind the CloseButton Command in my MainViewModel. Any help would be appreciated.
Here is my HeaderView.xaml.cs file
public partial class HeaderView : ContentView
{
public HeaderView ()
{
InitializeComponent ();
}
public static readonly BindableProperty CloseButtonClickedProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
public ICommand CloseButtonClick
{
get => (ICommand)GetValue(CloseButtonClickedProperty);
set => SetValue(CloseButtonClickedProperty, value);
}
}
Here is my close button code used in HeaderView.Xaml file
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
HeightRequest="65"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NameSpace.Views.HeaderView" x:Name="headerView">
<Image x:Name="CloseButton" Source="ic_closewhite.png" WidthRequest="20" HeightRequest="20" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CloseButtonClick, Source={x:Reference headerView}}" />
</Image.GestureRecognizers>
</Image>
</ContentView>
Here is where I am trying to use the command in my MainView.xaml.
<c:HeaderView CloseButtonClick ="{Binding CloseButtonClickCommand}"/>
But it throws an error:
You are doing correct but only one small thing missing that is the x:Name of the ContentView HeaderView.
Just include this line of code in Xaml of HeaderView.
x:Name="headerView"
Here is your modified Xaml:-
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
HeightRequest="65"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Name="headerView"
x:Class="NameSpace.Views.HeaderView" x:Name="headerView">
<Image x:Name="CloseButton" Source="ic_closewhite.png" WidthRequest="20" HeightRequest="20" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CloseButtonClick, Source={x:Reference headerView}}" />
</Image.GestureRecognizers>
</Image>
</ContentView>
public static readonly BindableProperty CloseButtonClickedProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
the issue is on this line,as the error message said,
event found for 'CloseButtonClick', or mismatching type between value
and property
you should change CloseButtonClickedProperty to CloseButtonClickProperty .
public static readonly BindableProperty CloseButtonClickedProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
public ICommand CloseButtonClick
{
get => (ICommand)GetValue(CloseButtonClickedProperty);
set => SetValue(CloseButtonClickedProperty, value);
}
to
public static readonly BindableProperty CloseButtonClickProperty = BindableProperty.Create(nameof(CloseButtonClick), typeof(ICommand), typeof(HeaderView), null);
public ICommand CloseButtonClick
{
get => (ICommand)GetValue(CloseButtonClickProperty);
set => SetValue(CloseButtonClickProperty, value);
}
Related
I made a ContentView with an Expander. I want to duplicate this Xaml code multiple times in an other Xaml file. But I want for each Expander a different Binding.
I linked this code (ContentView code):
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:expandable="clr-namespace:Expandable;assembly=ExpandableView"
x:Class="Hello.ExpandableView">
<ContentView.Content>
<expandable:ExpandableView Padding="5">
<expandable:ExpandableView.PrimaryView>
<Frame BackgroundColor="White" Padding="5" CornerRadius="10">
<StackLayout Orientation="Horizontal">
<Label x:Name="label" FontSize="16" TextColor="Black" FontAttributes="Bold" Padding="5" HorizontalTextAlignment="Start" HorizontalOptions="StartAndExpand"/>
<Image Source="arrow.png" WidthRequest="25" HeightRequest="25" Margin="5"/>
</StackLayout>
</Frame>
</expandable:ExpandableView.PrimaryView>
<expandable:ExpandableView.SecondaryViewTemplate>
<DataTemplate>
<Frame BackgroundColor="White" Padding="5" CornerRadius="10">
<Label Text="{Binding Tip1Uitleg}" FontSize="15" TextColor="Black" Padding="5"/>
</Frame>
</DataTemplate>
</expandable:ExpandableView.SecondaryViewTemplate>
</expandable:ExpandableView>
</ContentView.Content>
</ContentView>
namespace Hello
{
public partial class ExpandableView : ContentView
{
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged: (b, o, n) => (b as ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
}
}
To this code:
This works:
<local:ExpandableView Label="Hello"/>
But I want this. This does not work:
<?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:expandable="clr-namespace:Expandable;assembly=ExpandableView"
xmlns:local="clr-namespace:Hello"
x:Class="Hello.Health.HealthDetail"
Title="{Binding Name}">
<ContentPage.Content>
<ScrollView>
<StackLayout>
<Image Source="{Binding Image}"/>
<Label Text="{Binding Tip1Uitleg}" FontSize="15" TextColor="Black" Padding="10, 5, 10, 5"/>
<local:ExpandableView Label="{Binding Tip1}"/> //This is what it is all about
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
CodeBehind:
namespace Hello.Health
{
public partial class HealthDetail : ContentPage
{
public HealthDetail(HealthStrings healthStrings)
{
if (healthStrings == null)
throw new ArgumentNullException();
BindingContext = healthStrings;
InitializeComponent();
}
}
}
How do I make this work? I have to make this above more dynamic, but I do not know how.
BTW This also works:
<Label Text="{Binding Tip1}" />
I am sorry for the unclear explanation, I hope someone can help me.
Thank you for your time :)
You should not bind to 'this' since you are using a BindableProperty. Instead you should update the Label.Text property when the value of the BindableProperty changes.
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged:(b, o, n) => (b as ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
<?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="YourProject.ExpandableView">
<Grid>
<Label x:Name="label"/>
</Grid>
</ContentView>
Normally, when you want to binding a value for binableproperty, you could try the code below:
ExpandableView: I make a simple contentview with the same binableproperty for you reference.
<?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="XamarinDemo.Pages.ExpandableView">
<ContentView.Content>
<StackLayout>
<Label Text="Hello"></Label>
<Label x:Name="label"></Label>
</StackLayout>
</ContentView.Content>
</ContentView>
Code behind:
public partial class ExpandableView : ContentView
{
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged: (b, o, n) => (b as
ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
public ExpandableView()
{
InitializeComponent();
}
}
Usage:
<ContentPage.Content>
<local:ExpandableView Label="{Binding str}"></local:ExpandableView>
</ContentPage.Content>
Code Behind:
public partial class Page1 : ContentPage
{
public string str { get; set; }
public Page1()
{
InitializeComponent();
str = "okay";
this.BindingContext = this;
}
}
I use this template to create a button that's clickable for my application:
<?xml version="1.0" encoding="UTF-8"?>
<t:BaseButtonTemplate xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:t="clr-namespace:Japanese.Templates"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.Templates.Btn2" x:Name="this">
<StackLayout WidthRequest="50">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand, Source={x:Reference this}}"
CommandParameter="{Binding TapCommandParam, Source={x:Reference this}}"
NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
<Frame CornerRadius="25" BorderColor="{Binding FrameBorderColor, Source={x:Reference this}}"
BackgroundColor="{Binding FrameBackgroundColor, Source={x:Reference this}}"
HorizontalOptions="Center" VerticalOptions="Center" HasShadow="false" Padding="0"
WidthRequest="50" HeightRequest="50">
<Label TextColor="{Binding LabelTextColor, Source={x:Reference this}}"
Text="{Binding Text, Source={x:Reference this}}"
HorizontalOptions="Center" VerticalOptions="Center"
HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
FontFamily="FontAwesome5ProSolid" />
</Frame>
</StackLayout>
</t:BaseButtonTemplate>
The button is used like this:
<t:Btn2 LabelTextColor="#EA4335"
Text="{Binding ABtnText }"
TapCommand="{Binding ABtnCmd }" Grid.Column="0" />
And in my ViewModel I have this code:
public partial class PhrasesFrameViewModel : BaseViewModel
{
public ICommand ABtnCmd { get; }
public PhrasesFrameViewModel()
{
ABtnCmd = new Command(() => MessagingCenter.Send<PhrasesFrameViewModel>(this, "ABtn"));
}
public static readonly BindableProperty TapCommandProperty =
BindableProperty.Create(
"TapCommand", typeof(Command), typeof(BaseButtonTemplate),
defaultBindingMode: BindingMode.TwoWay,
defaultValue: default(Command));
public Command TapCommand
{
get { return (Command)GetValue(TapCommandProperty); }
set { SetValue(TapCommandProperty, value); }
}
public static readonly BindableProperty TapCommandParamProperty = BindableProperty.Create(nameof(TapCommandParam), typeof(object), typeof(BaseButtonTemplate), default(object));
public object TapCommandParam
{
get { return (object)GetValue(TapCommandParamProperty); }
set { SetValue(TapCommandParamProperty, value); }
}
public static readonly BindableProperty FrameBackgroundColorProperty =
BindableProperty.Create(
nameof(FrameBackgroundColor), typeof(Color), typeof(BaseButtonTemplate),
Color.FromHex("FFFFFF"));
public Color FrameBackgroundColor
{
get { return (Color)GetValue(FrameBackgroundColorProperty); }
set { SetValue(FrameBackgroundColorProperty, value); }
}
public static readonly BindableProperty FrameBorderColorProperty =
BindableProperty.Create(
nameof(FrameBorderColor), typeof(Color), typeof(BaseButtonTemplate),
Color.FromHex("EEEEEE"));
public Color FrameBorderColor
{
get { return (Color)GetValue(FrameBorderColorProperty); }
set { SetValue(FrameBorderColorProperty, value); }
}
I subscribe to the message like this:
MessagingCenter.Subscribe<PhrasesFrameViewModel>(this, "ABtn", async (s) => await Btn((int)Settings.aBtn, 1));
What I would like to do is to create some kind of effect when the button is clicked.
Does anyone have any suggestions on how I could do this? Note that the effect could be a background color change or anything that would indicate to the user that the button was pressed.
If you want to do it only in xamarin forms (without native renderers) you must subscribe in your custom button to the touch events. In these events, you can do for example a small-scale animation or change the background colour.
I code that I use often in my application so I created this template. With a lot of help from the user gannaway the code I have so far is this:
<?xml version="1.0" encoding="utf-8" ?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.SwitchViewCellTemplate"
x:Name="this">
<Grid VerticalOptions="CenterAndExpand" Padding="20,0" >
<local:StyledLabel Text="{Binding Text, Source={x:Reference this}}" HorizontalOptions="StartAndExpand" />
<local:StyledLabel IsVisible="{Binding IsVisible, Source={x:Reference this}}" TextColor="Gray" HorizontalOptions="End" Text="✓" />
</Grid>
</ViewCell>
Here's the code behind:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Japanese
{
public partial class SwitchViewCellTemplate : ViewCell
{
public event EventHandler SelectAction;
public SwitchViewCellTemplate()
{
InitializeComponent();
}
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(SwitchViewCellTemplate));
public static readonly BindableProperty IsVisibleProperty = BindableProperty.Create(nameof(IsVisible), typeof(bool), typeof(SwitchViewCellTemplate));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool IsVisible
{
get { return (bool)GetValue(IsVisibleProperty); }
set { SetValue(IsVisibleProperty, value); }
}
protected override void OnTapped()
{
base.OnTapped();
this.SelectAction?.Invoke(this, new EventArgs());
}
}
}
and the way I would like to use it:
<template:SwitchViewCellTemplate Text="{Binding [1].Name}"
IsVisible="{Binding [1].IsSelected}"
SelectAction="selectValue" />
Here is the method used to handle toggled:
void Handle_SelectAction(object sender, System.EventArgs e)
{
var viewCell = sender as ViewCell;
if (viewCell == null)
return;
}
Where selectValue is a function in the CS code behind of the pages where I use the template.
The code gives an error:
The type initializer for 'Japanese.SwitchViewCellTemplate' threw an exception.
Can anyone give me advice on what might be wrong that is causing this error.
To solve, an event can be added to the template.
XAML Template
<?xml version="1.0" encoding="utf-8" ?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.SwitchViewCellTemplate"
x:Name="this">
<Grid VerticalOptions="CenterAndExpand" Padding="20,0" >
<local:StyledLabel Text="{Binding Text, Source={x:Reference this}}" HorizontalOptions="StartAndExpand" />
<local:StyledLabel IsVisible="{Binding IsVisible, Source={x:Reference this}}" TextColor="Gray" HorizontalOptions="End" Text="✓" />
</Grid>
</ViewCell>
Add an event to your template's code-behind:
public partial class SwitchViewCellTemplate : ViewCell
{
public event EventHandler SelectAction;
public SwitchViewCellTemplate()
{
InitializeComponent();
}
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(SwitchViewCellTemplate),
default(string));
public static readonly BindableProperty IsVisibleProperty =
BindableProperty.Create(
nameof(IsVisible),
typeof(bool),
typeof(SwitchViewCellTemplate),
default(bool));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool IsVisible
{
get { return (bool)GetValue(IsVisibleProperty); }
set { SetValue(IsVisibleProperty, value); }
}
protected override void OnTapped()
{
base.OnTapped();
this.SelectAction?.Invoke(this, new EventArgs());
}
}
Page XAML
<template:SwitchViewCellTemplate Text="{Binding [1].Name}"
IsVisible="{Binding [1].IsSelected}"
SelectAction="Handle_SelectAction" />
Page Code-Behind
void Handle_SelectAction(object sender, System.EventArgs e)
{
}
I have tried to develop a usercontrol in Xamarin.Forms but I am not able to bind the controls of that Usercontrol using ViewModel.
My CustomeEntryUserControl is look like
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="LearningApp.UserControls.CustomeEntry"
xmlns:local="clr-namespace:LearningApp.Extension">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Entry Grid.Column="0" x:Name="entry" />
<local:RoundedButton Grid.Column="1" Text="X" BackgroundColor="Gray" TextColor="White" HeightRequest="20" WidthRequest="10" VerticalOptions="Center" Margin="-30,0,30,0" x:Name="cancelbtn" />
</Grid>
Code behind of this usercontrol is look like
public partial class CustomeEntry : Grid
{
public CustomeEntry()
{
InitializeComponent();
}
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(CustomeEntry), default(string));
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(CustomeEntry), typeof(ICommand), default(ICommand));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string PlaceHolder
{
get { return entry.Placeholder; }
set { entry.Placeholder = value; }
}
}
I have tried to use this control in one of my content page is like
<?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="LearningApp.Views.TriggersDemo.DataTriggers"
xmlns:local="clr-namespace:LearningApp.UserControls">
<StackLayout Orientation="Vertical">
<Label FontSize="Large" FontAttributes="Bold" Text="{Binding lblText}"></Label>
<local:CustomeEntry Text="{Binding Name}" Command="{Binding CancelCommand}" PlaceHolder="Enter Name"/>
<Button Command="{Binding CheckCommand}" Text="Check" />
</StackLayout>
</ContentPage>
code behind of above mentioned content page is
namespace LearningApp.Views.TriggersDemo
{
public partial class DataTriggers : ContentPage
{
public DataTriggers()
{
InitializeComponent();
this.BindingContext = new TriggersViewModel();
}
}
}
and My ViewModel contain the one Property like
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; RaisePropertyChanged(); }
}
Can anyone please guide how I can bind the Entry Text of UserControl to my ViewModel property Name direct?
In you CustomerEntry there is no control that displays the Text you're binding to.
You have to set up all the bindings in your custom control too.
You can also pass a handler to the TextProperty's `propertyChanged' parameter, and set other view's properties on behalf.
Remove the properties from the custom control and bind directly to the BindingContext which will be passed along (containing you viewmodel).
Then set Text="{Binding Text=.}" in your custom control's entry (same with Button's Command) to have it bind to the text from the BindingContext, in fact you can remove all your properties from the custom control, and bind directly to the 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.