In this blog post, you will learn how to use Appearing and Disappearing in MVVM ViewModel using EventToCommand Behaviour in Xamarin.Forms.
IntroductionXamarin.Forms code runs on multiple platforms - each of which has its own filesystem. This means that reading and writing files is most easily done using the native file APIs on each platform. Alternatively, embedded resources are a simpler solution to distribute data files with an app.
EventToCommand Behaviour
EventToCommandBehavior class is a reusable Xamarin.Forms custom behavior that executes a command in response to any event firing.
Following behavior properties must be set to use the EventToCommand behavior:
- EventName – the name of the event the behavior listens to(Ex: Apperaing).
- Command – the ICommand to be executed. The behavior expects to find the ICommand instance on the BindingContext of the attached control, which may be inherited from a parent element.
- Visual Studio 2017 or later (Windows or Mac)
Start by creating a new Xamarin.Forms project. You wíll learn more by going through the steps yourself.
Create a new or existing Xamarin forms(.Net standard) Project. With Android and iOS Platform.
Create BehaviourBase Class
Now, Create a Behaviour Base class Derived from Behavior and BindableObject
BehavourBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class BehaviorBase<T>: Behavior<T> where T : BindableObject | |
{ | |
public T AssociatedObject { get; private set; } | |
protected override void OnAttachedTo(T bindable) | |
{ | |
base.OnAttachedTo(bindable); | |
AssociatedObject = bindable; | |
if (bindable.BindingContext != null) | |
BindingContext = bindable.BindingContext; | |
bindable.BindingContextChanged += OnBindingContextChanged; | |
} | |
protected override void OnDetachingFrom(T bindable) | |
{ | |
base.OnDetachingFrom(bindable); | |
bindable.BindingContextChanged -= OnBindingContextChanged; | |
AssociatedObject = null; | |
} | |
void OnBindingContextChanged(object sender, EventArgs e) | |
{ | |
OnBindingContextChanged(); | |
} | |
protected override void OnBindingContextChanged() | |
{ | |
base.OnBindingContextChanged(); | |
BindingContext = AssociatedObject.BindingContext; | |
} | |
} |
Here, Create a EventToCommand Behaviour Class to convert your events to Commad and also implement bindable properties.
- EventName
- Command
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class EventToCommandBehavior: BehaviorBase<VisualElement> | |
{ | |
Delegate eventHandler; | |
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged); | |
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null); | |
public string EventName | |
{ | |
get { return (string)GetValue(EventNameProperty); } | |
set { SetValue(EventNameProperty, value); } | |
} | |
public ICommand Command | |
{ | |
get { return (ICommand)GetValue(CommandProperty); } | |
set { SetValue(CommandProperty, value); } | |
} | |
protected override void OnAttachedTo(VisualElement bindable) | |
{ | |
base.OnAttachedTo(bindable); | |
RegisterEvent(EventName); | |
} | |
protected override void OnDetachingFrom(VisualElement bindable) | |
{ | |
DeregisterEvent(EventName); | |
base.OnDetachingFrom(bindable); | |
} | |
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue) | |
{ | |
var behavior = (EventToCommandBehavior)bindable; | |
if (behavior.AssociatedObject == null) return; | |
string oldEventName = (string)oldValue; | |
string newEventName = (string)newValue; | |
behavior.DeregisterEvent(oldEventName); | |
behavior.RegisterEvent(newEventName); | |
} | |
void RegisterEvent(string name) | |
{ | |
if (string.IsNullOrWhiteSpace(name)) return; | |
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name); | |
if (eventInfo == null) | |
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName)); | |
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent"); | |
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this); | |
eventInfo.AddEventHandler(AssociatedObject, eventHandler); | |
} | |
void DeregisterEvent(string name) | |
{ | |
if (string.IsNullOrWhiteSpace(name) || eventHandler == null) | |
return; | |
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name); | |
if (eventInfo == null) | |
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName)); | |
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler); | |
eventHandler = null; | |
} | |
void OnEvent(object sender, object eventArgs) | |
{ | |
if (Command == null) return; | |
object resolvedParameter; | |
resolvedParameter = eventArgs; | |
if (Command.CanExecute(resolvedParameter)) | |
Command.Execute(resolvedParameter); | |
} | |
} |
In this step, I Create a common BaseViewModel for reusable purpose.
Note: I use RelayCommand Instead of Command. you can use Command.
Refresh
Refresh command indicate to Appearing Commad. Whatever you want to implement when page load time you can use RefrehCommad.
CleanUp
Cleanup command indicate to OnDisapearing. This CleanUpCommand when your page is dis appearing time it will be called.
BaseViewModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class BaseViewModel : ViewModelBase | |
{ | |
#region Fields | |
private RelayCommand _refreshCommand; | |
private RelayCommand _cleanupCommand; | |
#endregion | |
#region Properties | |
public RelayCommand RefreshCommand | |
{ | |
get | |
{ | |
return _refreshCommand ?? (_refreshCommand = new RelayCommand(this.Refresh)); | |
} | |
} | |
public RelayCommand CleanupCommand | |
{ | |
get | |
{ | |
return _cleanupCommand ?? (_cleanupCommand = new RelayCommand(this.Cleanup)); | |
} | |
} | |
#endregion | |
#region Methods | |
public virtual void Refresh() | |
{ | |
} | |
public override void Cleanup() | |
{ | |
base.Cleanup(); | |
} | |
#endregion | |
} |
Now, Use Refresh and CleanUp command from BaseViewMmodel in your Pages.
MainPageViewModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MainPageViewModel:BaseViewModel | |
{ | |
#region Fields | |
private ObservableCollection<Person> _persons; | |
#endregion | |
#region Constructor | |
public MainPageViewModel() | |
{ | |
} | |
#endregion | |
#region Properties | |
public ObservableCollection<Person> Persons | |
{ | |
get { return _persons; } | |
set { Set(() => Persons, ref _persons, value); } | |
} | |
#endregion | |
#region Methods | |
public override void Refresh() | |
{ | |
base.Refresh(); | |
this.Persons = new ObservableCollection<Person>(); | |
this.Persons.Add(new Person { PersonId = 1, Name = "Smith", Age = 22 }); | |
this.Persons.Add(new Person { PersonId = 2, Name = "Delpin", Age = 23 }); | |
this.Persons.Add(new Person { PersonId = 1, Name = "Raj", Age = 20 }); | |
this.Persons.Add(new Person { PersonId = 1, Name = "John", Age = 25 }); | |
} | |
public override void Cleanup() | |
{ | |
this.Persons = null; | |
base.Cleanup(); | |
} | |
#endregion | |
} |
Here, Implement EventToCommandBehaviour in your View.
Add Namespace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xmlns:behaviors="clr-namespace:XamarinStudy.Common.Behaviors" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ContentPage.Behaviors> | |
<behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding RefreshCommand}"/> | |
<behaviors:EventToCommandBehavior EventName="Disappearing" Command="{Binding CleanupCommand}"/> | |
</ContentPage.Behaviors> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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:behaviors="clr-namespace:XamarinStudy.Common.Behaviors" | |
x:Class="XamarinStudy.MainPage" Title="Bindable Layout"> | |
<ContentPage.Behaviors> | |
<behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding RefreshCommand}"/> | |
<behaviors:EventToCommandBehavior EventName="Disappearing" Command="{Binding CleanupCommand}"/> | |
</ContentPage.Behaviors> | |
<StackLayout x:Name="PersonList" BindableLayout.ItemsSource="{Binding Persons}" HorizontalOptions="FillAndExpand"> | |
<BindableLayout.ItemTemplate> | |
<DataTemplate> | |
<StackLayout Spacing="10" > | |
<Label Margin="20,0" Text="{Binding Name}"/> | |
<Label Margin="20,0" Text="{Binding Age}"/> | |
<BoxView HeightRequest="1" BackgroundColor="Black"/> | |
<StackLayout.GestureRecognizers> | |
<TapGestureRecognizer Command="{Binding BindingContext.SelectPersonCommand,Source={x:Reference PersonList}}" CommandParameter="{Binding PersonId}"/> | |
</StackLayout.GestureRecognizers> | |
</StackLayout> | |
</DataTemplate> | |
</BindableLayout.ItemTemplate> | |
</StackLayout> | |
</ContentPage> |
I hope you have understood how to use Appearing and Disappearing in MVVM ViewModel using EventToCommand Behaviour in Xamarin.Forms..
Thanks for reading. Please share your comments and feedback. Happy Coding :)