Corrado's Blog 2.0

Online thoughts of a technology funatic

Xamarin build server is too old?

This morning, no idea why, trying to compile a Xamarin.iOS app resulted in an error “Xamarin build server is tool old…” apparently without any reason since nothing has changed on my machine during the weekend. Tried also connecting to a different Mac machine but error was still there while compiling using Xamarin Studio on the Mac machine was ok.
After some investigation I’ve found the solution: looks like that “someone” changed my proxy settings (probably Fiddler) and that was causing the weird message.

Turning it off did the trick.

image

Hope this will help you in case you see this weird message too.

Declarative event handlers in Xamarin Android

In Android applications the UI components are totally isolated from associated activity so to ‘glue’ them you need to follow a ‘javascript like’ approach: find the element fist  and then interact with it. Let’s say you have a .axml file containing a button with id MyButton

 <Button
        android:id="@+id/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello" />

in the associated activity, to subscribe its Click event you have to write this code:

public class MainActivity : Activity
 {
  int count = 1;

  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);

   SetContentView(Resource.Layout.Main);
   Button button = FindViewById<Button>(Resource.Id.MyButton);
   button.Click += button_Click;
  }

  void button_Click(object sender, EventArgs e)
  {
   (sender as Button).Text = string.Format("{0} clicks!", count++);
  }
 }

If you, like me, come from XAML and love the declarative approach I’ve got a good new for you, there’s an alternative, just follow this steps:

1-Add a reference to Mono.Android.Export library

2-Declare you handler in .axml file this way:

<Button
        android:id="@+id/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
    android:onClick="myHandler"/>

3-Refactor the code in associated activity this way:

public class MainActivity : Activity
 {
  int count = 1;

  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);

   SetContentView(Resource.Layout.Main);
  }

  [Java.Interop.Export("myHandler")]
  public void button_Click(View v)
  {
   (v as Button).Text = string.Format("{0} clicks!", count++);
  }
 }

And you’re done!

As you see the trick is to export the function, using the Java.Interop.Export attribute that also allows you to use a export the method with a different name, leave it empty if you don’t need to differentiate.

Lot simpler, and cleaner… IMHO Smile

TranslateTo issue with Xamarin Forms 1.2.3

This Xamarin Forms snippets shifts a button left when clicked and restores it back when dialog is dismissed.

public static Page CreateMainPage3()
  {
   StackLayout container = new StackLayout() { Orientation = StackOrientation.Vertical };
   Button btn = new Button() { Text = "Ok" };
   btn.Clicked += async (s, e) =>
   {
    await btn.TranslateTo(-btn.Width, 0, 500);
    await MainPage.DisplayAlert("Test", "Hello", "Ok", "Cancel");
    await btn.TranslateTo(0, 0, 500);
   };

   container.Children.Add(btn);
   
   return MainPage = new ContentPage()
   {
    Content = container,
    Padding = new Thickness(10, 20, 10, 20)
   };
  }

Easy right? unfortunately it doesn’t work on Android (it is ok on Windows Phone and iOS) with Xamarin Forms version 1.2.3

The workaround is quite easy: use LayoutTo instead of TranslateTo, following code works on all platforms.

...
btn.Clicked += async (s, e) =>
   {
    Rectangle defaultRect = btn.Bounds;
    await btn.LayoutTo(new Rectangle(-btn.Width, btn.Y, btn.Width, btn.Height), 500);
    await MainPage.DisplayAlert("Test", "Hello", "Ok", "Cancel");
    await btn.LayoutTo(defaultRect, 500);
   };
 ...

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!
Older Posts »