Corrado's Blog 2.0

Online thoughts of a technology funatic

ToolbarItems in Xamarin Forms

A interesting Xamarin Forms feature well hidden inside documentation is that Page class exposes a collection of ToolbarItems. a ToolbarItem is an element that renders a “menu” on each platform letting you add elements like Menu on Android/iOS or ApplicationBar/MenuItems in Windows Phone.

To use Toolbaitems just create a new Xamarin Forms solutions and update all Xamarin related packages to latest version (there are several fixes related to Toolbaritems since v.1.0) then create a new MainView.xaml page (you can use code if you prefer, but I like XAML…) and add a couple of ToolBarItems to Page’s ToolbarItems collection:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="ToolbarItems.Views.MainView">
 <ContentPage.ToolbarItems>
  <ToolbarItem Name="Menu1" Activated="OnClick"  Order="Primary" Priority="0" />
  <ToolbarItem Name="Menu2" Activated="OnClick"  Order="Primary" Priority="1" />
 </ContentPage.ToolbarItems>

</ContentPage>

and this is code-behind:

void OnClick(object sender, EventArgs e)
  {
   ToolbarItem tbi = (ToolbarItem) sender;
   this.DisplayAlert("Selected!", tbi.Name,"OK");
  }

Change the startup page embedding MainView.xaml in a Navigation Page (this step is required in order to have menus available on Android platform)

namespace ToolbarItems
{
 public class App
 {
  public static Page GetMainPage()
  {
   return new NavigationPage(new MainView());
  }
 }
}

Here’s what you get on different platforms:

imageimageimage

please note how menus in iOS are in opposite direction compared to Android and Windows Phone, and how Windows Phone obviously miss the appropriate icons.

Let’s fix both issues with a little help from OnPlatform (used both resources and Property elements to cover both usage scenarios)

<?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="ToolbarItems.Views.MainView">
 <ContentPage.Resources>
  <ResourceDictionary>
   <OnPlatform x:Key="Priority1" x:TypeArguments="x:Int32"
      iOS="0"
      Android="1"
      WinPhone="1" />
   <OnPlatform x:Key="Priority2" x:TypeArguments="x:Int32"
      iOS="1"
      Android="0"
      WinPhone="0" />
  </ResourceDictionary>
 </ContentPage.Resources>

 <ContentPage.ToolbarItems>
  <ToolbarItem Name="Menu1" Activated="OnClick" Order="Primary" Priority="{StaticResource Priority1}"  >
   <ToolbarItem.Icon>
    <OnPlatform x:TypeArguments="FileImageSource"
      WinPhone="Toolkit.Content/ApplicationBar.Add.png" />
   </ToolbarItem.Icon>
  </ToolbarItem>
  <ToolbarItem Name="Menu2" Activated="OnClick" Order="Primary" Priority="{StaticResource Priority2}" >
   <ToolbarItem.Icon>
    <OnPlatform x:TypeArguments="FileImageSource"
     WinPhone="Toolkit.Content/ApplicationBar.Check.png" />
   </ToolbarItem.Icon>
  </ToolbarItem>
 </ContentPage.ToolbarItems>
</ContentPage>

Of course you can use Icon property on each platform (see Android sample below)

image

The role of Order property depends on platform, on Windows Phone using Secondary  creates MenuItems, on Android it adds entries to Page menu and on iOS render menu as horizontally aligned buttons.

Android

image

Windows Phone

image

iOS

image

I took a while for me to know about this feature, glad I’ve found it.

Xamarin.Forms.Behaviors v.1.1.0

I’ve pushed an update to Xamarin.Forms.Behaviors library, fixed some bugs and added Relative Commanding to EventToCommand Behavior.

What is Relative Commanding?

It is a way to let EventToCommand invoke a Command that is exposed by a ViewModel that’s not part of actual BindingContext, typical example is when you are inside an ItemTemplate (ViewCell in Xamarin Forms) and you need to invoke a command that’s hosted inside another viewmodel.

To support this feature I’ve added two new properties to EventToCommand: CommandName and CommandContext, former is the name (string) of the Command you want to invoke, latter is the BindingContext that exposes that command.

How can you link CommandContext with desired BindingContext? Use the new RelativeContext markup extension exposed by Behaviors library to ‘link’ a BindingContext to another (CommandContext in case of EventToCommand)

Here’s a sample taken from GitHub repo.

MainViewModel exposes both an ObservableCollection of Items and a NickSelectedCommand and is also bound to MainPage’s BindingContext, here’s how you can let ListView’s items invoke MainViewModel command.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
      xmlns:b="clr-namespace:Xamarin.Behaviors;assembly=Xamarin.Behaviors"
        x:Class="Xamarin.Behaviors.Demo.Views.MainView"
      x:Name="MainPage"> 

  <ListView ItemsSource="{Binding Items}"
      IsGroupingEnabled="false"
      RowHeight="60">
   <ListView.ItemTemplate>
    <DataTemplate>
     <ViewCell>
      <StackLayout Orientation="Horizontal" Padding="10" >
       <StackLayout Orientation="Vertical"  HorizontalOptions="FillAndExpand" Spacing="-50"  >
        <Button Text="{Binding NickName}">
         <b:Interaction.Behaviors>
          <b:BehaviorCollection>
           <b:EventToCommand CommandNameContext="{b:RelativeContext MainPage}"
                 EventName="Clicked"
                 CommandName="NickSelectedCommand"
                 CommandParameter="{Binding NickName}" />
          </b:BehaviorCollection>
         </b:Interaction.Behaviors>
        </Button>
        
       </StackLayout>
      </StackLayout>

     </ViewCell>
    </DataTemplate>
   </ListView.ItemTemplate>
  </ListView>
  
  
 </StackLayout>
</ContentPage>

As you see we ‘linked’ CommandNameContext to the BindingContext associated to MainPage element through RelativeContext extension an we told EventToCommand that button’s Clicked event should invoke a Command named “NickSelectedCommad” also note that original BindingContext is preserved so we can safely use binding for the CommandParameter property.

Happy Behavioring… Smile

Application wide resources in Xamarin Forms

Xamarin Form’s XAML infrastructure is very similar to Windows counterpart (and I thank Xamarin for that!) unfortunately in current version a feature is not there yet: Application wide resources that is resources  that are shared among all application pages.

In this blog post I’ll show you how to add this feature to a Xamarin Forms application.

Step 1

Create a new Xamarin Forms application (shared)

image

Step 2

Create a CoreApplication class that inherits from View, this class provides a ResourceDictionary property and can be lately extended with other Application features.

namespace Xamarin.Forms
{
 public class CoreApplication:View
 {
 }
}

Step 3

Create an App class that inherits for CoreApplication that is splitted between XAML and associated code-behind.

<?xml version="1.0" encoding="utf-8" ?>
<CoreApplication xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="SharedResources.App">
 <CoreApplication.Resources>
  <ResourceDictionary>
   ... app wide resources here...
  </ResourceDictionary>
 </CoreApplication.Resources> 
</CoreApplication>

code behind:

namespace SharedResources
{
 public partial class App : CoreApplication
 {
  static App current;

  public App()
  {
   InitializeComponent();
  }

  public static App Current
  {
   get
   {
    return current ?? (current = new App());
   }
  }

  public Page GetMainPage()
  {
   return new MainView();   
  }
 }
}

As you see, together with standard XAML initialization call InitializeComponent the call exposes a Current static application returning a singleton App instance and Xamarin Forms standard method GetMainPage that returns application’s main page.

Step 4

Since App class has changed we need to update the code generated by Xamarin Forms template that retrieve application’s main page in each platform, thank to Current property modification is very easy, just a line of code for each supported platform.

Android

namespace SharedResourced.Droid
{
 [Activity(Label = "SharedResourced", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
 public class MainActivity : AndroidActivity
 {
  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);

   Xamarin.Forms.Forms.Init(this, bundle);

   SetPage(SharedResources.App.Current.GetMainPage());
  }
 }
}

iOS

namespace SharedResourced.iOS
{
 [Register("AppDelegate")]
 public partial class AppDelegate : UIApplicationDelegate
 {
  UIWindow window;

  public override bool FinishedLaunching(UIApplication app, NSDictionary options)
  {
   Forms.Init();

   window = new UIWindow(UIScreen.MainScreen.Bounds);

   window.RootViewController = SharedResources.App.Current.GetMainPage().CreateViewController();

   window.MakeKeyAndVisible();

   return true;
  }
 }
}

Windows Phone

namespace SharedResourced.WinPhone
{
 public partial class MainPage : PhoneApplicationPage
 {
  public MainPage()
  {
   InitializeComponent();

   Forms.Init();
   Content = SharedResources.App.Current.GetMainPage().ConvertPageToUIElement(this);
  }
 }
}

Step 6

Since we need to lookup application wide resources in XAML, let’s use one of the less known XAML features: Custom Markup Extension. As in Windows, defining a Custom Markup Extension in Xamarin Forms is just a matter of implementing the IMarkupExtension interface (not sure about requirement of class name ending with *Extension but I’ll follow the convention)

Here’s the code

namespace Extensions
{
 [ContentProperty("Key")]
 public class GlobalResourceExtension : IMarkupExtension
 {
  public string Key { get; set; }
  public object ProvideValue(IServiceProvider serviceProvider)
  {
   if (this.Key == null)
    throw new InvalidOperationException("you must specify a key in {GlobalResource}");
   if (serviceProvider == null)
    throw new ArgumentNullException("serviceProvider");

   object value;
   bool found = App.Current.Resources.TryGetValue(this.Key, out value);
   if (found) return value;
   throw new ArgumentNullException(string.Format("Can't find a global resource for key {0}", this.Key));
  }
 }
}

No rocket science, just a simple lookup into Application’s resource dictionary to get required resource.

Step 7

Time to test our work, let’s add some dummy resources to App.Xaml and consume them in a XAML page.

<CoreApplication xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="SharedResources.App">
 <CoreApplication.Resources>
  <ResourceDictionary>
   <LayoutOptions x:Key="hOptions" Alignment="Start" />
   <x:String x:Key="color">Red</x:String>
   <x:String x:Key="color2">#CC00FF00</x:String>
   <OnPlatform x:Key="Angle" x:TypeArguments="x:Double">
    <OnPlatform.iOS>0</OnPlatform.iOS>
    <OnPlatform.Android>-15</OnPlatform.Android>
    <OnPlatform.WinPhone>90</OnPlatform.WinPhone>
   </OnPlatform>
  </ResourceDictionary>
 </CoreApplication.Resources>
</CoreApplication>

MainView.Xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
      xmlns:e="clr-namespace:Extensions;assembly=SharedResourced"
        x:Class="SharedResourced.MainView">
 <StackLayout Spacing="30">
  <Label Text="Hello" 
     VerticalOptions="{e:GlobalResource hOptions}" 
     TextColor="{e:GlobalResource color2}" 
     HorizontalOptions="Center" />

  <Label Text="Hello2" 
     VerticalOptions="{e:GlobalResource hOptions}" 
     Font="Large" 
     TextColor="{e:GlobalResource color}" 
     HorizontalOptions="Center"
     Rotation="{e:GlobalResource Angle}"/>
 </StackLayout>
</ContentPage>

Note the presence of xaml namespace “e” that contains our custom markup extension.

Here you go, just a few steps and now you have Application wide resources instead of repeating them in each page.

Here’s the Windows Phone and Android output (sorry no Mac machine connected at this moment Winking smile)

image  image

Introducing Xamarin Forms Behaviors

The goal of this post is to introduce you to the Xamarin.Forms.Behavior package available on NuGet, if you landed here I presume you already know what Xamarin Forms is, if not, follow this link so you’ll understand why so many developers are excited about it.

Now that I can assume you’re a Xamarin Forms master, let’s concentrate on Behaviors. Once I read Xamarin Forms documentation I was really happy to see that you can design cross-platforms user interfaces using XAML and that the XAML support in Xamarin Forms is nearly identical to the one available in Windows development apart some minor differences.

If you don’t know what a Behavior is I can summarize it for you in this sentence: The capabity to add code inside a UI described using XAML” the question now is: Why should I add code inside XAML, hasn’t code behind created just for this? well, yes and no, if you know MVVM (if not, you should!) you’ll know that the entire logic should reside inside the VieModel associated with the View and that communication between View and ViewModel should happen (in a perfect world) through Databinding.

Unfortunately in “real” world this is not always possible and you have to use code to make things work, often this code resides in code behind and for this reason is not testable and not even reusable.

Let’s take an example: A simple view made up of two Entry elements and a Button, the View has a ViewModel associated to its BindingContext and we want the button to be enabled only when both Entry fields are not empty and it’s enabled state must toggle “live” while user typing.

This is the XAML contained inside Xamarin Forms’s PCL project:

<?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="Xamarin.Behaviors.Demo.Views.MainView">
 <StackLayout>
  <Entry Placeholder="Enter Firstname" />
  <Entry  Placeholder="Enter Lastname" />
  <Button Text="Ok" Command="{Binding TestCommand}" />    
 </StackLayout>
</ContentPage>

and here’s the ViewModel:

public class MainViewModel : INotifyPropertyChanged
 {
  public event PropertyChangedEventHandler PropertyChanged;

  private string firstName = "Nome";
  private string lastName = "Cognome";
  private Command testCommand;
  private Command<object> unfocusedCommand;
  private string message;
  private string welcomeMessage; 
  
  public string FirstName
  {
   get { return this.firstName; }

   set
   {
    if (value != this.firstName)
    {
     this.firstName = value;
     this.RaisePropertyChanged();
     this.TestCommand.ChangeCanExecute();
    }
   }
  }
  
  public string LastName
  {
   get { return this.lastName; }

   set
   {
    if (value != this.lastName)
    {
     this.lastName = value;
     this.RaisePropertyChanged();
     this.TestCommand.ChangeCanExecute();
    }
   }
  }
  
  public string Message
  {
   get  {return this.message; }

   private set
   {
    if (value != this.message)
    {
     this.message = value;
     this.RaisePropertyChanged();
    }
   }
  }  
  public string WelcomeMessage
  {
   get { return this.welcomeMessage;}

   set
   {
    if (value != this.welcomeMessage)
    {
     this.welcomeMessage = value;
     this.RaisePropertyChanged();
    }
   }
  }
  
  public Command TestCommand
  {
   get
   {
    return this.testCommand ?? (this.testCommand = new Command(
      () =>
      {
       this.WelcomeMessage = string.Format("Hello {0} {1}", this.FirstName, this.LastName);
      },
      () =>
      {
       return !string.IsNullOrEmpty(this.FirstName) && !string.IsNullOrEmpty(this.LastName);
      }));
   }
  }

  public Command<object> UnfocusedCommand
  {
   get
   {
    return this.unfocusedCommand ?? (this.unfocusedCommand = new Command<object>(
      (param) =>
      {
       this.Message = string.Format("Unfocused raised with param {0}", param);
      },
      (param) =>
      {
       // CanExecute delegate
       return true;
      }));
   }
  }
  
  protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  {
   PropertyChangedEventHandler handler = PropertyChanged;
   if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
  }
 }

ViewModel is associated with the View’s constructor for brevity:

public partial class MainView
 {
  public MainView()
  {
   InitializeComponent();
   this.BindingContext = new MainViewModel();
  }
 }

As you see the Button is connected to ViewModel’s TestCommand via Databinding and thanks to ICommand interface it is enabled only when both ViewModel’s FirstName and LastName properties are not empty.

Now the hardest part: How do we update those properties when Entry content changes?

Easy: we subscribe Entry’s TextChanged method and when it fires we update associated property. Cool, but wouldn’t it be nice if we could encapsulate this logic into a reusable component, usable in XAML, so that we don’t need to reinvent the wheel each time?

Here’s where Behaviors can help you.

Install Xamarin.Forms.Behaviors Package from NuGet and  and create a class that inherits from Behavior<T> where <T> is the UI component that the behavior will attach to, in our case the Entry element.

public class TextChangedBehavior : Behavior<Entry>
 {
  public static readonly BindableProperty TextProperty = BindableProperty.Create<TextChangedBehavior, string>(p => p.Text, null, propertyChanged: OnTextChanged);

  private static void OnTextChanged(BindableObject bindable, string oldvalue, string newvalue)
  {
   (bindable as TextChangedBehavior).AssociatedObject.Text = newvalue;
  }

  public string Text
  {
   get { return (string)GetValue(TextProperty); }
   set { SetValue(TextProperty, value); }
  }

  protected override void OnAttach()
  {
   this.AssociatedObject.TextChanged += this.OnTextChanged;
  }

  private void OnTextChanged(object sender, TextChangedEventArgs e)
  {
   this.Text = e.NewTextValue;
  }

  protected override void OnDetach()
  {
   this.AssociatedObject.TextChanged -= this.OnTextChanged;
  }
 }

Behavior and Behavior<T> both have OnAttach and OnDetach methods that gets invoked when the behavior is attached/detached from parent UI element, so we subscribe TextChanged event and when it triggers we update behavior’s bindable property Text.

I’ll be you’re now wondering: How do I use it in my XAML? very easy, here’s the updated XAML for Entry element (just first one indicated for brevity)

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:b="clr-namespace:Xamarin.Behaviors;assembly=Xamarin.Behaviors"
        x:Class="Xamarin.Behaviors.Demo.Views.MainView">
 <StackLayout>
  <Entry Placeholder="Enter Firstname" >
   <b:Interaction.Behaviors>
    <b:BehaviorCollection>
     <b:TextChangedBehavior Text="{Binding FirstName, Mode=TwoWay}" />     
    </b:BehaviorCollection>
   </b:Interaction.Behaviors>
  </Entry>
  ...
  </StackLayout>
</ContentPage
  

After adding a xmlns pointing to Xamarin.Forms.Behavior namespace we “inject” the code into XAML, so now as we type on Entry the Firstname property it’s updated (and vice versa of course thanks to INotifyPropertyChanged and Two Way binding mode.)

One of the real advantages of using Behaviors in Windows Development is that they’re visually supported by Expression Blend design tool, so you don’t even need to write any XAML, just drag the behavior and configure it using point and click Smile unfortunately since we don’t even have a XAML designer in Xamarin Forms typing is the only available solution at the moment.

If you think the syntax is quite boring I agree, that’s why inside the project on GitHub I added a XML snippet that generates the surrounding code for you, just grab it and import it in Visual Studio, add the behavior syntax and press Ctrl+K+S

image

and you’ll have the plumbing code added for you, don’t forget to add required xmlns directive/s.

xmlns:b="clr-namespace:Xamarin.Behaviors;assembly=Xamarin.Behaviors"

since it’s not added automatically by the snippet.

Am not a Xamarin Studio expert so I don’t know if it support XML Expansions, if so send me the snippet and I’ll add it to the project.

Here’s the XAML taken from the example available on GitHub:

<Entry Placeholder="Enter Firstname" >
   <b:Interaction.Behaviors>
    <b:BehaviorCollection>
     <b:TextChangedBehavior Text="{Binding FirstName, Mode=TwoWay}" />
     <b:EventToCommand EventName="Unfocused" Command="{Binding UnfocusedCommand}" CommandParameter="FirstName" />
    </b:BehaviorCollection>
   </b:Interaction.Behaviors>
  </Entry>

the example shows two behaviors included in the package, TextChangedBehavior and EventToCommand, a behavior that invokes a Command when an event occurs.

Congratulations! you’re now able to write your own behavior, group them in a portable library and reuse it in every Xamarin Forms project.

If you’re already a XAML developer you already know what behaviors are and I hope you’ll like to have them in Xamarin Forms, if not I encourage you to play with it, personally can’t even think using XAML with MVVM without them.

Ok, now let’s dream about a Xamarin Forms designer supporting the same Behavior infrastructure as Expression Blend, am I asking too much? we’ll see.

Cheers!

NuGet Package: here

GitHub repo: here