Corrado's Blog 2.0

Online thoughts of a technology funatic

UserControls in Xamarin Forms

While Xamarin Forms have a rich set of controls (a.k.a. Views in Xamarin documentation) sometimes you need to create something that is an aggregate of existing controls plus custom logic. For this requirement the Windows platform provides you a UserControl that is a surface where you can drag the controls that make up the UI and write related logic within it.
This seems to lack on Xamarin Forms at the moment.

Well, that’s not true, since you can easily create UserControls your own in Xamarin Forms, let’s see how with an example (see below)

image image

Lat’s say I need to populate a list of Entries whose content has to be validated and if not valid a feedback has to be provided to the user. Since we don’t like to repeat ourselves and since this might be a requirement we might also have in future I decided to create a custom control that contains all the validation logic and exposes a set of properties that let me customize the runtime behavior of the control.

Here’s the MainView’s XAML of the previous screenshots:

<?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:c="clr-namespace:UserControl;assembly=UserControl"
        x:Class="UserControl.MainView">

 <StackLayout Padding="10" >
  <Label Text="UserControls in action!" x:Name="MyLabel" Font="Bold,Large"  />
  <c:SmartEntry Header="Enter Username (min 3, max 8 chars)"
         ValidMode="MinMax"
         Min="3"
         Max="8"
         InvalidText="Sorry, username is not valid"
         Text="{Binding Username, Mode=TwoWay}"
         />
  <c:SmartEntry Header="Enter Email"
         ValidMode="Email"
         InvalidText="Whoops! invalid email..."
         Text="{Binding Email, Mode=TwoWay}"
         />

  <Label Font="Large" Text="{Binding Info}" TextColor="Green" />

 </StackLayout>
</ContentPage>

I’m sure you noted the SmartEntry component that is our UserControl, let’s see how I created it.

Everything starts from a UserControl class that inherits from Frame

namespace UserControl
{
 using Xamarin.Forms;

 public class UserControl : Frame
 {
  private Dictionary<string, object> cache = new Dictionary<string, object>();

  public UserControl()
  {
   this.Padding = new Thickness(0, 0, 0, 0);
  }

  protected T FindByViewPrivate<T>(string name)
  {
   if (this.cache.ContainsKey(name))
   {
    return (T)this.cache[name];
   }

   Type t = this.GetType();
   FieldInfo fi = t.GetRuntimeFields().FirstOrDefault(f => f.Name == name);
   if (fi == null) throw new NullReferenceException(string.Format("Field {0} not found.", name));
   T value = (T)fi.GetValue(this);
   this.cache.Add(name, value);
   return value;
  }
 }
}

This class just resets default padding added by Frame so that content fills the container and a FindByViewPrivate<T> method that gives us access to private UI element instances created by LoadFromXaml method when it parses the XAML.

now let’s see the “real” UserControl, XAML first:

<?xml version="1.0" encoding="utf-8" ?>
<c:UserControl xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     xmlns:c="clr-namespace:UserControl;assembly=UserControl"
     x:Class="UserControl.SmartEntry">
 <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
  <StackLayout Orientation="Horizontal">
   <Label x:Name="HeaderLabel" HorizontalOptions="Start"  />
   <Frame Padding="10,0,0,0">
    <Label TextColor="Red" x:Name="InvalidTextLabel" IsVisible="false"  />
   </Frame>
  </StackLayout>
  <Entry x:Name="TextEntry" />
 </StackLayout>
</c:UserControl>

then code-behind (I’ve removed Validate() method code for brevity, get the full code from the link at the end of this post)

namespace UserControl
{
 public enum ValidationModes
 {
  Email,
  MinMax
 }

 public partial class SmartEntry : UserControl
 {
  public SmartEntry()
  {
   InitializeComponent();

   TextEntry.TextChanged += (s, e) =>
   {
    bool isTextValid = this.Validate(e.NewTextValue);
    InvalidTextLabel.IsVisible = !isTextValid;
    if (isTextValid) this.Text = e.NewTextValue;
   };
  }

  public ValidationModes ValidMode { get; set; }

  public int Min { get; set; }
  public int Max { get; set; }

  public string InvalidText
  {
   get { return InvalidTextLabel.Text; }
   set { InvalidTextLabel.Text = value; }
  }

  public string Header
  {
   get { return HeaderLabel.Text; }
   set { HeaderLabel.Text = value; }
  }

  public static readonly BindableProperty TextProperty =
    BindableProperty.Create<SmartEntry, string>(
    p => p.Text, null, propertyChanged: OnTextChanged);

  private static void OnTextChanged(BindableObject bindable, string oldvalue, string newvalue)
  {
   SmartEntry origin = (SmartEntry)bindable;
   Entry textBox = origin.FindByViewPrivate<Entry>("TextEntry");
   textBox.Text = newvalue;
  }

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

I’ve added some simple public properties: Min,Max,Header,InvalidText and a BindableProperty Text so that we can bind it to our ViewModel for further processing.

As you see, inside OnTextChanged I use FindByViewPrivate<Entry> to retrieve the proper control instance from the static method.

All properties are used inside MainView’s XAML to customize each UserControl differently.

If you want to see the example in action download the code here

Have fun Winking smile

Force assembly linking in Xamarin.iOS projects

I’ve updated Xamarin.Forms.Behaviors package to v 1.2 to fix an issue reported by alexandremblah (thank you!) that was preventing the package to work on iOS, the issue was that Xamarin.Behaviors.dll couldn’t be loaded.

image

After a few tests I’ve used JetBrains DotPeek to see what gets deployed to emulator

image

and, as you see, Xamarin.Behaviors dll is missing, that’s the cause of the exception.

In iOS project there’s an option that might solve the problem:

image

but unfortunately changing Linker option to “Link all assemblies” didn’t fix, probably because all Behavior stuff is handled in XAML which is loaded at runtime, so there is no code using Behaviors types.

The only option I’ve found to force iOS linker to deploy Behaviors library is to include some code on iOS project that interacts with some entities in the library, so I’ve added an Infrastructure static class that exposes a Init method that does practically nothing.

public static class Infrastructure
 {
  private static DateTime initDate;
  public static void Init()
  {
   initDate = DateTime.UtcNow;
  }
 }

And inside iOS project you have to add a call to Infrastructure’s Init method.

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

   //Added to prevent iOS linker to strip behaviors assembly out of deployed package.
   Xamarin.Behaviors.Infrastructure.Init();

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

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

   window.MakeKeyAndVisible();

   return true;
  }

with this magic trick assemblies gets included and behaviors work fine:

image

Android and Windows Phone projects don’t require this method invocation.

Enjoy and thank for your feedback.

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

Add “intellisense” to Xamarin .axml files

When you manually edit .axml files inside Visual Studio 2013 you don’t have any minimal intellisense support, and, as Visual Studio user, you know how frustrating is typing without any kind of help.

image

Since editing the same file using the XML editors brings you a ‘partial’ intellisense i tried to find what was the difference and finally found how to enable it also inside Android designer source view.

  1. 1-With Designer in source view, select Visual Studio’s xml menu and then Schemas…
  2. image
  3. 2-Navigate to C:\Program Files (x86)\MSBuild\Xamarin\Android and select android-layout-xml.xsd file.
  4. 3-Click Ok to confirm and dismiss the dialog.
  5. Here’s what you now get when typing android: in source view:
  6. image
  7. Of course, this is not the same experience we have in XAML, but better than nothing.
  8. After adding the schema, the first time you add a new Android layout Visual Studio asks you to trust a new file, just select Trust and everything will work as usual in future.
  9. Enjoy!

Scroll with snapping in Windows Phone 8

I’m working on a Windows Phone 8 app that has an “unconventional” UI as it does not follow Windows Phone UX guidelines (it’s a company private app) and so it has home page made up of several screens horizontally aligned that user can pan.

Untitled

I started wrapping the screens inside a horizontally oriented WrapPanel and content, as expected, scrolled.
Mission accomplished? well not really: Content was scrolling but final experience was poor because of missing snapping feature, it was extremely easy lo leave home page with more than one screen visible.

image

To overcome this issue I decides to create a Blend Behavior that attached to a ScrollViewer would take care of smoothly bring into view the correct screen depending on scroll direction.
Solution wasn’t as immediate as previous one since I decided to use an ItemsControl as ScrollViewer’s content since I have the same requirements in other views where content is databound and I had to “dig into” ScrollViewer and attach to both horizontal and vertical scrollbars (yes, I need to support both scrolling direction) but at the end it worked.

Yeah! but, there’s another UX issue: ScrollViewer has the ‘compression’ feature, the one often used to create the famous “Pull to refresh” functionality in lists. Since final experience was not acceptable and since I haven’t found a reliable way of disabling it I abandoned this 2nd solution and decided to go handling all scrolling details.

Enter the SnappingScrollViewer

I won’t bother you with a long code listing (you can get the source code here) but what I did basically was:

  1. -Create a class that inherits from Canvas
  2. -Register Canvas Manipulation events
  3. -Use ManipulationMode.Delta event to set Canvas left/top offset to scroll content
  4. -Use ManipulationMode.Completed event to detect current scrolling position and scroll the screen to proper position using an animation.

Since animation target requires a dependency property and my class is based on Canvas SetLeft/SetTop method I used an old XAML trick adding a custom ScrollOffset dependency property and invoking proper method inside property’s changed event:

protected virtual void OnScrollOffsetChanged(double oldValue, double newValue)
        {
            if (this.IsVertical)
            {
                SetTop(this.content, newValue);
            }
            else
            {
                SetLeft(this.content, newValue);
            }
        }

content is ScrollViewer’s ItemsControl that I get into Loaded event.

private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.content = (ItemsControl)this.Children.First();
            this.totalPages = (int)(this.IsVertical ? (this.content.ActualHeight / this.ItemSize) : (this.content.ActualWidth / this.ItemSize));
            this.snapAmount = this.ItemSize * this.Inertia;
            this.itemIndex = this.InitialIndex;
            if (this.IsVertical)
            {
                SetTop(this.content, -this.InitialIndex * this.ItemSize);
            }
            else
            {
                SetLeft(this.content, -this.InitialIndex * this.ItemSize);
            }
        }

Use is very simple:

<smoothScroller:SnappingScrollViewer x:Name="LayoutRoot"
                                   ItemSize="480"
                                   InitialIndex="2"
                                   IsVertical="False"
                                   Background="White">
        <ItemsControl Background="#FFE01818">
            <ListBoxItem>
                <Grid Background="Aqua"
                      Width="480"
                      Height="800" />
            </ListBoxItem>
            <ListBoxItem>
                <Grid Background="YellowGreen"
                      Width="480"
                      Height="800" />
            </ListBoxItem>

            <ListBoxItem>
                <Grid Background="Orange"
                      Width="480"
                      Height="800" />
            </ListBoxItem>
            <ListBoxItem>
                <Grid Background="Red"
                      Width="480"
                      Height="800" />
            </ListBoxItem>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </smoothScroller:SnappingScrollViewer>

Limitations in sample code: All content must have the same dimension and no support of dynamically added items (did that in production code but wanted to keep demo simple Smile)

Go grab the code and enhance it depending on your needs.

Note for Windows Phone 8.1: ScrollViewer in Windows Phone 8.1 has a HorizontalSnapPointType property that can be used to “snap” content, so this XAML will work as expected

<ScrollViewer HorizontalScrollMode="Enabled"
                      HorizontalScrollBarVisibility="Visible"
                      HorizontalSnapPointsType="Mandatory">
            <StackPanel Orientation="Horizontal">
                <Grid Height="800"
                      Background="#FF1EAA4B"
                      Width="480" />
                <Grid Height="800"
                      Background="#FFDAB611"
                      Width="480" />
                <Grid Height="800"
                      Background="#FF9C0EC5"
                      Width="480" />
            </StackPanel>
        </ScrollViewer>

Unfortunately Compression effect is still present Sad smile if anyone knows how to disable it just let me know, I’m more than interested.

Enjoy!

 

Xamarin: Infinite scrolling list in iOS app

I’ve spend the last few weeks studying Xamarin, not because I’m considering abandoning the Windows platform but because I think it’s clear that, as developer, we need to take note that there are other big platforms with which it is right to live with.

While not yet mature and in some cases quite cumbersome, my experience with it was highly positive and I absolutely recommend it in case you need to create Android and/or iOS applications.

This post comes from a need I had during development of a iOS application: Create an infinite scrolling list of data starting from paged data coming from a REST service.

Note: I’m a Xamarin beginner so this might not be the perfect solution, but it worked fine in my case.

To get infinite scrolling I created a custom UITableSource

public class BookedCarsTableViewSource : UITableViewSource
    {
        private readonly DataService dataService;
        private readonly PagedResult<BookedCarResponse> firstPage;
        private readonly List<BookedCarResponse> bookedCars;
        private int pageIndex;
        private bool isFetching;

        private const string cellId = "bookedCarCell";

        public BookedCarsTableViewSource(DataService dataService, PagedResult<BookedCarResponse> firstPage)
        {
            this.dataService = dataService;
            this.firstPage = firstPage;
            this.bookedCars = firstPage.Result.ToList();
            this.pageIndex = 0;
        }

        public override int RowsInSection(UITableView tableview, int section)
        {
            return (int)Math.Max(this.bookedCars.Count, this.firstPage.TotalCount);
        }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            int index = indexPath.Row;
            UITableViewCell cell = tableView.DequeueReusableCell(cellId) ?? new UITableViewCell(UITableViewCellStyle.Subtitle, cellId);
            BookedCarResponse bookedCar = this.bookedCars[index];
            cell.TextLabel.Text = bookedCar.CarPlate;
            cell.DetailTextLabel.Text = bookedCar.CompanyName;            
            if (!this.isFetching && this.pageIndex < this.firstPage.TotalPages && index > this.bookedCars.Count * 0.8)
            {
                this.isFetching = true;
                Task.Factory.StartNew(this.LoadMore);
            }

            return cell;
        }

        private async void LoadMore()
        {
            this.pageIndex++;
            var nextPage = await this.dataService.GetBookedCars(this.pageIndex, this.firstPage.PageSize);
            this.bookedCars.AddRange(nextPage.Result);
            this.isFetching = false;
        }
    }

As you see the trick is inside GetCell, when requested index is near the end of currently available items I spin a new request and add results to bookedCars collection.

In order to get initial block of items I used this code inside related controller:

public class BookedCarsScreenController : UITableViewController
    {
        private PagedResult<BookedCarResponse> firstPage;

        public override async void ViewDidLoad()
        {
            base.ViewDidLoad();
            this.firstPage = await DataManager.Current.GetBookedCars(0, 30);
            this.TableView.Source = new BookedCarsTableViewSource(DataManager.Current, firstPage);
            this.TableView.ReloadData();
        }
    }

I had to invoke TableView’s ReloadData otherwise list was appearing initially empty.

Note that since I’m using Subtitle layout I didn’t find the way to use  iOS 6 automatic cell reuse mode.

Hope it helps! Smile

Windows 8: Is app running inside Visual Studio?

Sometimes you need to run some additional debugging code when your app is launched from a development environment (e.g from Visual Studio), of course there are compiler directives for this but I’ve found a property inside WinRT that can make this even easier.

bool isInsideVs = Windows.ApplicationModel.Package.Current.IsDevelopmentMode;

please note that property indicates Development mode, this means that it will probably check whether app is running from \Program Files\WindowsApps folder so if you launch the just compiled app from Start menu on same machine it will still returns true.

Try to sideload the app and in this case it will have the value false.

 

Older Posts »