Corrado's Blog 2.0

Online thoughts of a technology funatic

Xamarin Forms: CarouselView in action

Xamarin Forms are getting better with each new release, version 2.2, actually in preview, includes new interesting addition like Effects and CarouselView.

CarouselView replaces the now deprecated CarouselPage with a more flexible control that can be embedded in any page and can have any size you want, being curious I wanted to see it in action.

I created a new Xamarin Forms project and updated all projects NuGet Packages to version 2.2.0.5-pre2 (you have to select “Include prerelease” option to have it listed since, at the moment, it hasn’t officially released yet.

image

I suddenly added a MainView xaml page to the PCL project and set it as MainPage inside App.cs

public class App : Application { public App() { // The root page of your application MainPage = new MainView(); } }

CarouselView inherits from ItemView so it requires a collection of items associated to it’s ItemSource property, I then created an array of Persons and associated to CarouselView with this code

public partial class MainView : ContentPage { public MainView() { this.InitializeComponent(); Person[] persons = { new Person() { Name = "Corrado", ImageUri = "male.png" }, new Person() { Name = "Giulia", ImageUri = "female.png" } }; this.MyCarouselView.ItemsSource = persons; CarouselView v; } } public class Person { public string Name { get; set; } public string ImageUri { get; set; } }

MyCarouselView is the CarouselView I previously added to MainView.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:testCarouselView="clr-namespace:TestCarouselView;assembly=TestCarouselView" x:Class="TestCarouselView.MainView"> <CarouselView x:Name="MyCarouselView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" /> </ContentPage>

Great, but we’re missing something: The ItemTemplate. but since I want to use a different template for each page I decided to use another recent addition to Xamarin Forms: the DataTemplateSelector, so I created this class that inherits from abstract DataTemplateSelector.

public class CarouselTemplateSelector : DataTemplateSelector { public DataTemplate MaleTemplate { get; set; } public DataTemplate FemaleTemplate { get; set; } protected override DataTemplate OnSelectTemplate(object item, BindableObject container) { Person person = (Person)item; switch (person.ImageUri) { case "male.png": return MaleTemplate; case "female.png": return FemaleTemplate; default: throw new ArgumentOutOfRangeException(); } } }

So simple that don’t think it requires a detailed explanation, it just returns proper DataTemplate depending on the name of ImageUri, ok, not very professional but this is just a demo right? Smile

I generally like to have TemplateSelectors instantiated via xaml together with their associated template definition in one place, so I added them to MainView xaml resources, here’s complete markup:

<?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:testCarouselView="clr-namespace:TestCarouselView;assembly=TestCarouselView" x:Class="TestCarouselView.MainView"> <ContentPage.Resources> <ResourceDictionary> <!--Female template--> <DataTemplate x:Key="FeMaleTemplate"> <StackLayout BackgroundColor="Pink" Orientation="Horizontal"> <Image Source="{Binding ImageUri}" VerticalOptions="Center" Margin="50,0,0,0" WidthRequest="100" HeightRequest="200" /> <Label VerticalOptions="Center" Margin="60,0,0,0" Text="{Binding Name}" TextColor="Black" FontSize="30" /> </StackLayout> </DataTemplate> <!--Male template--> <DataTemplate x:Key="MaleTemplate"> <Grid BackgroundColor="Aqua"> <Image Source="{Binding ImageUri}" VerticalOptions="Start" Margin="00,50,0,0" WidthRequest="100" HeightRequest="200" /> <Label VerticalOptions="Center" HorizontalOptions="Center" Margin="0,500,0,0" Text="{Binding Name}" TextColor="Black" FontSize="30" /> </Grid> </DataTemplate> <!--Template selector--> <testCarouselView:CarouselTemplateSelector x:Key="CarouselTemplateSelector" MaleTemplate="{StaticResource MaleTemplate}" FemaleTemplate="{StaticResource FeMaleTemplate}" /> </ResourceDictionary> </ContentPage.Resources> <!--Carousel View--> <CarouselView PositionSelected="OnPositionSelected" x:Name="MyCarouselView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ItemTemplate="{StaticResource CarouselTemplateSelector}" /> </ContentPage>

From the xaml you’ll immediately recognize the two (simple) DataTemplates, the custom DataTemplateSelector , how it gets associated to CarouselView ItemTemplate but if you look closely you’ll also recognize a nice addition to Forms v2.2: Margin property!

Yes we can now stop using nested views with Padding to fine tune control position inside a Page, well done Xamarin!

If you want to be informed when the position of CarouselView changes just subscribe PositionChanged event, in my case I mapped it to this method:

private void OnPositionSelected(object sender, SelectedPositionChangedEventArgs e) { Debug.WriteLine(e.SelectedPosition.ToString()); }

We can now run the sample code and we’ll get this outputs (Android/iOS)

Android       ios

CarouselView is a great new entry, in special case if you want to create applications based on sliding views (quite common today) there’s just one feature I miss: Orientation, at the moment looks like you can only slide horizontally, hope Xamarin will consider it for final release.

Using Xamarin Forms Effects

Version 2.1 of Xamarin Forms introduced Effects, a nice alternative to custom renderers when all you need is to tweak some properties of the platform native control, they should be seen as an alternative to a custom renderer not as a substitute.

Let’s quickly see how they work, let’s suppose we want to limit the amount of text that a user can type inside an entry, something that’s not natively possible with Xamarin Forms (at the time of this writing…)

Create a new Xamarin Forms project and upgrade Xamarin.Forms assemblies to latest stable version greater than 2.1 , in my case is 2.1.0.6529

image

Effects are a mix of platform specific code and code that resides in application PCL library, let’s start with the PCL and create a class that uses RoutingEffect  as base class:

public class MyEntryEffect : RoutingEffect { public MyEntryEffect() : base("MyCompanyName.EntryEffect") { } public int MaxLength { get; set; } }

As you can see the constructor of this class invokes base constructor passing the fully qualified name of the platform specific effect to be created (“MyCompanyName.EntryEffect” more details on this soon)

It’s time to apply our Effect (or as I prefer ‘extension’) to a Xamain Forms Entry, in my project I’ve added a MainView.xaml page and this is related XAML.

<?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:demoEffects2="clr-namespace:DemoEffects2;assembly=DemoEffects2" x:Class="DemoEffects2.MainView"> <StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"> <Entry Placeholder="Try to type more than 5 chars.." > <Entry.Effects> <demoEffects2:MyEntryEffect MaxLength="5" /> </Entry.Effects> </Entry> </StackLayout> </ContentPage>

Quite easy to understand: We added our custom MyEntryEffect effect to Entry’s Effects collection and set it’s MaxLength property to 5.

Is now time to switch to platform specific projects and implement the code that reads the value of MaxLength property and applies this limit to platform specific control.

Let’s start with Android:

[assembly: ResolutionGroupName("MyCompanyName")] //Note: only one in a project please... [assembly: ExportEffect(typeof(EntryEffect), "EntryEffect")] namespace DemoEffects2.Droid { public class EntryEffect : PlatformEffect { protected override void OnAttached() { try { //We get the effect matching required type, we might have more than one defined on the same entry var pclEffect = (DemoEffects2.MyEntryEffect)this.Element.Effects.FirstOrDefault(e => e is DemoEffects2.MyEntryEffect); TextView editEntry = this.Control as TextView; editEntry?.SetFilters(new Android.Text.IInputFilter[] { new Android.Text.InputFilterLengthFilter(pclEffect.MaxLength) }); } catch (Exception ex) { //Catch any exception } } protected override void OnDetached() { } protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) { base.OnElementPropertyChanged(args); try { if (args.PropertyName == "Your property name") { //Update control here... } } catch (Exception ex) { Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message); } } } }

Inside the Android project I have created an EntryEffect class that inherits from PlatformEffect and implemented two familiar overrides: OnAttached and OnDetached.

As you might expect the first is invoked when Effect is applied to the control and can be used to initialize the property of Android’s native control while OnDetached is called when the effect is removed and can be used to perform any cleanup. 

From inside this methods we have access to three fundamental properties:

Container: The platform specific control used to implement the layout.

      • Control: The platform specific counterpart of Xamarin Forms control.

Element: The Xamarin Forms control being rendered.

Since Effect can be added to Effects collection of any control the code must take this into consideration and degrade gracefully in case actions cannot be completed due to a control type mismatch.

Inside OnAttached we retrieve the PCL effect so that we can read it’s MaxLenght property and we cast the Control property to a TextView, if casting fails we simply do nothing otherwise we add a filter that limits the number of typed chars inside the TextView.

Even if not used in this sample, the code includes OnElementPropertyChanged override that can be used when you want to be notified when a property of the control changes (e.g. IsFocused) and do something when this happens.

Last, but absolutely not least come the two attributes ResolutionGroupName and ExportEffect

ResolutionGroupName : Allows you to define a custom namespace for you effects to prevent naming collision, it must be used once in the platform specific project.

ExportEffect: Is the name that’s used by initial effects discovery process and it accepts the type of the effect it is applied to and the name you want to export for discovery.

The concatenation of ResolutionGroupName and ExportEffect id is used by RoutingEffect class (see it’s base constructor in preceding code) for proper identification.

As for custom renderers is not necessary to implement the effect for each class, if undefined it simply gets ignored.

Here’s the iOS effect version:

[assembly: ResolutionGroupName("MyCompanyName")] //Note: only one in a project please... [assembly: ExportEffect(typeof(EntryEffect), "EntryEffect")] namespace DemoEffects2.iOS { public class EntryEffect : PlatformEffect { protected override void OnAttached() { try { //We get the effect matching required type, we might have more than one defined on the same entry var pclEffect = (DemoEffects2.MyEntryEffect)this.Element.Effects.FirstOrDefault(e => e is DemoEffects2.MyEntryEffect); UITextField editEntry = this.Control as UITextField; if (editEntry != null) { editEntry.ShouldChangeCharacters = (UITextField textField, NSRange range, string replacementString) => { // Calculate new length var length = textField.Text.Length - range.Length + replacementString.Length; return length <= pclEffect.MaxLength; }; } } catch (Exception ex) { //Catch any exception } } protected override void OnDetached() { } } }

Simpler, but more flexible, Xamain Forms effects represent a valid alternative to Renderers, I’m pretty sure that we’ll see many open source effects coming from th Xamarin community.

If you want to know more about Effects, this is the link to follow.

Happy Effecting.

Xamarin Forms preview with Gorilla Player

One of the major complaints about Xamarin Forms is the lack of designer with relative preview so, at the time of this writing, the development process is made up of a continuous sequence of: write XAML, deploy, see result, stop, edit XAML and try again, not a very convenient and productive way to work Sad smile

GorillaPlayer is a tool from a company named UXDivers that provides real time XAML preview on any Emulator/Simulator speeding up development process.

Note: GorillaPlayer is actually in beta and available via invite only, go request your invite here: www.gorillaplayer.com the player is available for both Visual Studio and Xamarin Studio (both Windows and iOS)

Once you get the invite, download the installer for your platform, enter the invitation code and let the installer complete installation, I encourage you to select the “Install Player + SDK + Samples” option since it contains a fundamental component (a.k.a. The Player)

image
If everything goes well, you should now have a new element in your tray area (on Windows Platform)

image

Right clicking the icon you’ll see all Gorilla Player’s options, I suggest you to have a look at Getting Started Walkthrough

image:

In order to see your XAML output you must install the Gorilla Player App in target emulator/simulator (in alternative using included Gorilla Player’s SDK, the player can be integrated directly in your app, see SDK page for more details) the player will try to connect with the host running on your machine

image

and once connection is completed (you have both automatic and manual setup options)  you’ll see the monkey smiling and ready to render your XAML

image

Let’s see some XAML then!

While the player app is running, create a brand new Xamarin Forms app (or open an existing one…) and open/add a XAML page, you should see the preview live on the emulator/simulator, if not check Gorilla Player’s option under: Tools->Gorilla Player (in Visual Studio) if not connected select the Connect option and check Follow me option

image

Note: using Stick to this XAML will let you freeze the rendered XAML while working on another file.

If Gorilla can’t render your XAML you’ll see an error message like this:

image

Otherwise you’ll get the final output, here’s a demo XAML fragment:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="GorillaTest.Views.MyView"> <ContentPage.Resources> <ResourceDictionary> <Style x:Key="MyLabelStyle" TargetType="Label"> <Setter Property="HorizontalOptions" Value="Center" /> <Setter Property="VerticalOptions" Value="CenterAndExpand" /> <Setter Property="FontSize" Value="20" /> </Style> </ResourceDictionary> </ContentPage.Resources> <StackLayout BackgroundColor="Teal"> <Image Source="icon.png" WidthRequest="100" HeightRequest="100" /> <Label Text="Gorilla Player Rocks!" Style="{StaticResource MyLabelStyle}" TextColor="White" /> </StackLayout> </ContentPage>

image

As you see the Player supports every XAML element including Images, Styles, Resources, etc it also support ContentViews (see here)

But what about design time data? : If you have a ListView I presume you want to see how it renders at runtime right? luckily Gorilla Player has a great support for design time data too, with several options (see here) probably the quickest one is to use add a json file with sample data to your project.

Let’s take this XAML as example (taken from Gorilla’s demo MyCoolCompanyApp)

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyCoolCompanyApp.MyPeople" xmlns:common="clr-namespace:UXDivers.Artina.Player;assembly=UXDivers.Artina.Player.Common" BackgroundColor="#455a64" xmlns:local="clr-namespace:MyCoolCompanyApp;assembly=MyCoolCompanyApp"> <ContentPage.Content> <Grid> <Image Opacity="0.5" x:Name="img" Source="bridge_bg.png" Scale="1.5" Aspect="AspectFill"/> <StackLayout Padding="10,30,20,0"> <ListView ItemsSource="{Binding .}" SeparatorVisibility="None" BackgroundColor="Transparent" SeparatorColor="#DFDFDF" HasUnevenRows="false" RowHeight="120"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <local:MyPeopleTemplate /> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </Grid> </ContentPage.Content> </ContentPage>

The output rendered by Gorilla Player is:

image

Awesome! but since we are at design time, were do the ListView data come from? If you look at PCL project you’ll see that it includes a SampleData.json file

image

with this content:

{ "MyPeopleTemplate.xaml": { "Name": "John Silverstain", "City": "MELBOURNE", "Department": "Marketing", "Color": "Red", "Age": 29, "Followers": 243, "Photo": "friend_thumbnail_27.jpg" }, "MyPeople.xaml": [ { "Name": "John Silverstain", "City": "MELBOURNE", "Department":"Marketing", "Color":"Red", "Age":29, "Followers":243, "Photo":"friend_thumbnail_27.jpg" }, { "Name": "Pam Tailor", "City": "SIDNEY", "Department":"Design", "Age":32, "Followers":24, "Photo":"friend_thumbnail_75.jpg" }, { "Name": "Casy Niman", "City": "HOBART", "Department":"Accounts", "Age":58, "Followers":267, "Photo":"friend_thumbnail_93.jpg" }, { "Name": "Gorge Tach", "City": "NEWCASTLE", "Department":"Design", "Age":29, "Followers":127, "Photo":"friend_thumbnail_55.jpg" }, { "Name": "Cristina Maciel", "City": "HOBART", "Department":"Mobile Dev.", "Age":32, "Followers":80, "Photo":"friend_thumbnail_31.jpg" }, { "Name": "Simon Deuva", "City": "MELBOURNE", "Department":"Media", "Age":58, "Followers":420, "Photo":"friend_thumbnail_34.jpg" } ] }

As you see, the file contains a set of sample data, in json format, that will be associated to each page (MyPeopleTemplate.xaml and MyPeople.xaml in this case) ideally simulating the same data that the associated ViewModel will provide at runtime. in the docs you’ll find alternative design time solutions like using a Json data class or a Plain object.

While in beta, the product is already very stable and a total life saver if you do Xamarin Forms development so I encourage you to give it a try and help the team fixing all issues so that we can get an official v 1.0 soon.

Issues can be filed here.

Happy Gorilla rendering! Smile

Adding a splash screen to Xamarin Forms apps

Every Xamarin Forms app should ship with a splash screen, it is the first thing a user see and it contributes to reduce the perceived application boot time.

Adding one is quite easy, let’s go from simpler to harder.

The simpler: Windows Phone

Just replace SplashScreenImage.jpg (720×1280 pixels) with your own app launch image in the Windows Phone project and you’re done.

image

The harder: iOS

If you follow iOS documentation you’ll know that adding your own launch screen is just a matter of adding the proper images to the project via info.pList options.

image

unfortunately once you do that you’ll still see the blue background with Xamarin Logo at startup, to fix it delete the content of Launch Storyboard option into info.pList and you’re done (no idea why template adds that storyboard inside Resources folder)

image

The hardest: Android

Adding a splash screen requires following steps:

image

1-Add the splash screen image into Resources\drawable folder (and all the variants you want to support) in previous screenshot file is named splash.png

2-Create a new folder under Resources and name it values

3-Add an xml file into values folder (name is not important, in my case I named it Styles.xml)

4-Add this content to xml file

<?xml version="1.0" encoding="utf-8" ?>
<resources>
    <style name="Theme.Splash" parent="android:Theme">
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:windowNoTitle">true</item>
    </style>
</resources>

5-Add a new activity to the project and add this code (of course you can safely remove the delay before StartActivity method)

[Activity(Theme = "@style/Theme.Splash", //Indicates the theme to use for this activity
             MainLauncher = true, //Set it as boot activity
             NoHistory = true)] //Doesn't place it in back stack
    public class SplashActivity : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            System.Threading.Thread.Sleep(3000); //Let's wait awhile...
            this.StartActivity(typeof(MainActivity));
        }
    }

6-Remove the MainLauncher=true from original activity since this is the new activity that will be launched at startup.

Hope this helps…

Application wide resources (reloaded)

Back in September 2014 I blogged about adding application wide resources to Xamarin Forms applications, that technique is no longer needed since starting from v 1.3 Xamarin added support to app wide resources into Xamarin Forms core.

So what it this post about? It is about adding (and using) them in a more user-friendly way.

Since v 1.3 you can create a resource that can be reachable from all pages this way:

public class App : Application
    {
        public App()
        {
            this.Resources = new ResourceDictionary
            {
                {"TextColor", Color.FromHex("00FF00")}
            };

            // The root page of your application
            this.MainPage = new MainView();
        }
    }

And use the resource from a XAML page this way:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App1.MainView">
    <Label Text="Hello from Xamarin Forms" 
             VerticalOptions="Center" 
             HorizontalOptions="Center" 
             TextColor="{StaticResource TextColor}" />
</ContentPage>

Ok, It works but is not very friendly, resource name is not listed in XAML Intellisense (powered by Resharper of course) and as XAML lover I’d like to define my application resources in XAML the same way I do in a page.

Luckily you can and it’s very easy:

1- Delete App.cs file

2-Add a new Forms XAML Page and name it App.cs

image

3-Make App.cs inherit from Application instead of ContentPage

public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }
    }

4-Replace the generated XAML with following one, don’t forget to substitute [YourNamespaceHere] with your own’s application namespace

<Application xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="[YourNamespaceHere].App">
    <Application.Resources>
        <ResourceDictionary>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Your project should now look like this:

image

and you can add your resources inside ResourceDictionary as in following example:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="[YourNamespaceHere].App">
    <Application.Resources>
        <ResourceDictionary>
            <Color x:Key="TextColor">Red</Color>
        </ResourceDictionary>
    </Application.Resources>
</Application>

And now, your resource will work as expected but it will also be listed by Intellisense

image

Definitively more friendly than using code (IMHO)

Hope to see this feature added to Xamarin Forms template soon.

Behaviors for Xamarin Forms v2.0

I’ve pushed version 2.0 of my behavior implementation for Xamarin Forms and moved it to a new location on GitHub: https://github.com/corradocavalli/Corcav.Behaviors

The reason for this is that, in order to prevent conflict with Xamarin API I’ve renamed the root namespace so upgrading to this version will break your code and I’m really sorry for this, but I’m sure it won’t take too long to fix it.

I’ve also removed old nuget package and replaced with this one : ’https://www.nuget.org/packages/Corcav.Behaviors/

Version 2.0 uses Xamarin Forms 1.3.4 and Unified API project as iOS demo.

Sorry for breaking your code, my fault using Xamarin as assembly name Sad smile (lesson learned), honestly didn’t expect such success, and I thank you for that.

Get device unique identifier in Xamarin Forms

Last week I introduced some ISV to the wonderful world of Xamarin and while discussing Xamarin Forms a few of them asked how to get an identifier that uniquely identifies a device.

I had the same issue in the past with a Windows Phone application so I know how retrieve it on this platform and I remember speaking with the guy that was working on the same app for iOS that he told me that Apple changed the policy so the API that was used in the past was no longer available and he had to find a workaround, more on this later.

The answer to the original question is quite easy from the architectural side: Just use a Dependency Service and you’re done, here are the steps:

Let’s create a IDevice interface in the common/shared project and let’s add a GetIdentifier method

public interface IDevice
 {
  string GetIdentifier();  
 }

Once done you can easily get device unique identifier within shared code using this snippet:

IDevice device = DependencyService.Get<IDevice>();
string deviceIdentifier = device.GetIdentifier();

Let’s now implement device specific code, starting from Windows Phone, add this class to Windows Phone project and add ID_CAP_IDENTITY_DEVICE capability.

[assembly: Xamarin.Forms.Dependency(typeof(WinPhoneDevice))]
namespace XFUniqueIdentifier.WinPhone
{
 public class WinPhoneDevice : IDevice
 {
  public string GetIdentifier()
  {
   byte[] myDeviceId = (byte[])Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("DeviceUniqueId");
   return Convert.ToBase64String(myDeviceId);
  }
 }
}

Now add following class to Android project:

[assembly: Xamarin.Forms.Dependency(typeof(AndroidDevice))]
namespace XFUniqueIdentifier.Droid
{
 public class AndroidDevice : IDevice
 {
  public string GetIdentifier()
  {
   return Settings.Secure.GetString(Forms.Context.ContentResolver, Settings.Secure.AndroidId);
  }
 }
}

And now the hardest part: iOS developer used to get device identifier using Device UniqueIdentifier api but this has deprecated by Apple so an alternative has to be found.

After some investigations (also considered generating unique id at startup but this would fail if app is reinstalled) I found this post on Xamarin forums so kudos goes to the original author.

It’s now time to add a new class to iOS project with following code:

[assembly: Xamarin.Forms.Dependency(typeof(IOSDevice))]
namespace XFUniqueIdentifier.iOS
{
 using System.IO;
 using System.Runtime.InteropServices;

 public class IOSDevice : IDevice
 {
  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern uint IOServiceGetMatchingService(uint masterPort, IntPtr matching);

  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern IntPtr IOServiceMatching(string s);

  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern IntPtr IORegistryEntryCreateCFProperty(uint entry, IntPtr key, IntPtr allocator, uint options);

  [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
  private static extern int IOObjectRelease(uint o);

  public string GetIdentifier()
  {
   string serial = string.Empty;
   uint platformExpert = IOServiceGetMatchingService(0, IOServiceMatching("IOPlatformExpertDevice"));
   if (platformExpert != 0)
   {
    NSString key = (NSString) "IOPlatformSerialNumber";
    IntPtr serialNumber = IORegistryEntryCreateCFProperty(platformExpert, key.Handle, IntPtr.Zero, 0);
    if (serialNumber != IntPtr.Zero)
    {
     serial = NSString.FromHandle(serialNumber);
    }

    IOObjectRelease(platformExpert);
   }

   return serial;
  }  
}

And you’re done, have fun and make a good use of device unique id. 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.

Older Posts »