Xamarin.Tip – Build Your Own In-App Developer Options

This post is a continuation of building gesture based “easter eggs” into your Xamarin apps (native or Forms).

In this post, we are going to continue from these posts:
Xamarin.Tip – Add Easter Eggs to UWP with Key Combos
Xamarin.Tip – Add Easter Eggs on Shake

to talk about how we can use these gestures in Debug mode to give ourselves some shortcuts for testing and moving through our application quicker.

To breakdown the process setup – we added shake handlers (and keyboard shortcuts for UWP) that can invoke any contextual code in our application. We talked about using this for funny easter eggs, but this functionality can be made into something super useful for us.

I call this “Contextual Developer Options”. The idea is take that easter egg handler and use it to display some contextual options that can be controlled page by page or view by view. This can be toggling some UI updates, auto-navigating through the app, testing different scenarios, etc.

In this example we’ll be using MVVM and Xamarin.Forms to demonstrate the possibilities, but the same idea can be applied to any other pattern or practice. Basically we need to:

  • Register dev options to whatever context we want
  • Determine what context we are in
  • Display the actionable dev options

Before starting, I suggest looking at something like Allan Ritchie’s incredibly useful UserDialogs package https://github.com/aritchie/userdialogs

We’ll use it in our examples.

Setting Up Developer Options

First things first, let’s define our developer options.

DevelopmentOption.cs

public class DevelopmentOption
{
    public string Title { get; set; }
    public Action Action { get; set; }
}

Now, like I said, our example will be doing this in MVVM and we can use the current page the user is on as the context we want to apply.

I’ll start by creating a BasePageViewModel that we can use to set up our developer options and execute the action

BasePageViewModel.cs

public abstract class BasePageViewModel : ViewModelBase
{
    protected List<DevelopmentOption> _developerOptions;
    private bool _isShowingDeveloperOptions = false;

    public BasePageViewModel()
    {
        _developerOptions = new List<DevelopmentOptions>();
    }

    /// <summary>
    /// Shows the developer options. This should be called after a native easter egg such as a shake.
    /// </summary>
    public virtual async Task ShowDeveloperOptionsAsync()
    {
        if (_developerOptions.Any() && !_isShowingDeveloperOptions)
        {
            var titles = _developerOptions.Select(d => d.Title);
            _isShowingDeveloperOptions = true;
            var actionResult = await UserDialogs.Instance.ActionSheetAsync("Developer Options", "Cancel", null, null, titles.ToArray());
            _isShowingDeveloperOptions = false;
            // see if an option was selected
            if (titles.Contains(actionResult))
            {
                // call it if we find it.
                var option = _developerOptions.FirstOrDefault(d => d.Title == actionResult);
                option?.Action();
            }
        }
    }

    /// <summary>
    /// Sets up the developer options.
    /// </summary>
    protected virtual void SetupDeveloperOptions()
    {
        _developerOptions.Add(new DevelopmentOption()
        {
            Title = "Go to debug page",
            Action = () => UserDialogs.Instance.Toast("Not implemented")
        });
    }

    /// <summary>
    /// Adds the developer option.
    /// </summary>
    /// <param name="title">Title.</param>
    /// <param name="action">Action to perform when selected.</param>
    protected void AddDeveloperOption(string title, Action action)
    {
        _developerOptions.Add(new DevelopmentOption()
        {
            Title = title,
            Action = action
        });
    }
}

Alright let’s breakdown what’s going on here.

Our BasePageViewModel has a List that represents our different options for the given page. Then we have some protected methods we can use in our extended PageViewModels to setup different options.

In our SetupDeveloperOptions method, we can setup any option we want for the page, and we put a universal “Go to debug page” example action that is there on every page.

So here’s an example of a useful ViewModel that sets up a login page developer option.

LoginPageViewModel.cs

public class LoginPageViewModel : BasePageViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
    protected override void SetupDeveloperOptions()
    {
        AddDeveloperOption("Use test user", () => 
        {
            Email = "mytestuser@mydomain.com";
            Password = "myP@ssw0rd";
        });
    }
}

So what we want on this login page is to be able to shake the device and see the Action Sheet that shows “Use test user” and when selected, it should fill out the fields on the page automatically.

Now that our setup is done, let’s wire up accessing these developer options.

Wiring It Up

We need to be able to access our Page’s ViewModel in order to execute the developer options when the shake happens. To do this, we can access the current page via the Xamarin.Forms.Application.Current static accessor. Then use the MainPage property to get around.

I like to add a simple helper property getter on my App class for this:

App.xaml.cs

public class App : Application
{
    // ...

    // assuming MainPage is a NavigationPage. You can do some extra logic if it isn't
    public ContentPage CurrentPage => (MainPage as NavigationPage)?.Navigation?.NavigationStack?.Last()
    // ...
}

Now in our native app logic, where we were executing the easter egg we can call:

// we don't want developer options in production 🙂
#if DEBUG
await ((App.Current as App)?.CurrentPage?.BindingContext as BasePageViewModel)?.ShowDeveloperOptionsAsync();
#endif

So now if we are in our LoginPage and our BindingContext is set to our LoginPageViewModel, our shake should reveal the action sheet!

Conclusion

We can make our lives a whole lot easier when testing and running through our app by giving ourselves easier and contextual options throughout the entire application.

I’ve personally used this for some pretty awesome and intense stuff like:

  • Filling out forms with different values
  • Changing styles/themes of the app to easily compare 2 different UIs
  • Test different states of a page such as if a user is logged in or not
  • Test error scenarios
  • Build a page that shows logs of all interactions and background tasks in the app and use the developer options to navigate to that page whenever to see those custom logs live (even when not attached to the debugger)
  • Execute custom native code to make debugging easier
  • Navigate quickly to the page deep in the app I am currently working on

Remember to still write unit and UI tests for your app too! This is meant to be something to make real hands-on testing even easier too.

It has saved me hundreds of hours easily. Let me know if you end up implementing something like this too!

For now, I don’t have any complete open source project to demo this, but if enough of you want to see a full example and screenshots and different scenarios, I’ll consider putting a full project together. Let me know in the comments or on twitter!


If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Advertisements

Xamarin.NuGet – DynamicWrapLayout Announcement!

It’s been a little while since I’ve posted about any new Xamarin Controls or updates, but here’s a great one!

I needed to create a layout that could bind to a collection of data in Xamarin.Forms that fit to a dynamic grid that also scaled to larger devices and orientation changes. I thought about creating a new custom renderer that uses the RecyclerView with a GridLayoutManager and a UICollectionView with a custom layout. However, I didn’t need to bind to tons of data, so I decided to create a new control that is entirely Xamarin.Forms – No custom renderers!

I’ve called it the DynamicWrapLayout since it was inspired by the WrapLayout from Charles Petzold and David Britch.

Get it on NuGet: https://www.nuget.org/packages/DynamicWrapLayout/
Get the source on GitHub: https://github.com/SuavePirate/DynamicWrapLayout

Because it is all Xamarin.Forms, it should work on all the platforms that Forms supports! So use it everywhere! I’ll create another post about how I built it if you want to work on your own implementation, but for now, you can read the documentation on the control below.

Documentation

DynamicWrapLayout

A Xamarin.Forms layout for creating dynamically wrapped views. Inspired by the WrapLayout example: https://developer.xamarin.com/samples/xamarin-forms/UserInterface/CustomLayout/WrapLayout/

Installation

It’s on NuGet! https://www.nuget.org/packages/DynamicWrapLayout/

Install-Package DynamicWrapLayout

Be sure to install in all projects that use it.

Usage

There are two key properties that make this control useful – the ItemsSource (like a ListView) and the DataTemplate (although, you can also just add children to the view – it does both!)
Be sure to wrap it in a ScrollView though

XAML

Add the xmlns:

xmlns:suave="clr-namespace:SuaveControls.DynamicWrapLayout;assembly=SuaveControls.DynamicWrapLayout"

Use it in your View:

<ScrollView>
    <suave:DynamicWrapLayout ItemsSource="{Binding Items}" HorizontalOptions="Fill">
        <suave:DynamicWrapLayout.ItemTemplate>
            <DataTemplate>
                <StackLayout BackgroundColor="Gray" WidthRequest="120" HeightRequest="180">
                    <Label Text="{Binding .}" TextColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
                </StackLayout>
            </DataTemplate>
        </suave:DynamicWrapLayout.ItemTemplate>
    </suave:DynamicWrapLayout>
</ScrollView>

Don’t like data-binding and want to just use child views? You can do that too!

<ScrollView>
    <suave:DynamicWrapLayout HorizontalOptions="Fill">
      <StackLayout BackgroundColor="Gray" WidthRequest="120" HeightRequest="180">
          <Label Text="0" TextColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
      </StackLayout>
      <StackLayout BackgroundColor="Gray" WidthRequest="120" HeightRequest="180">
          <Label Text="1" TextColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
      </StackLayout>
      <StackLayout BackgroundColor="Gray" WidthRequest="120" HeightRequest="180">
          <Label Text="2" TextColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
      </StackLayout>
      <StackLayout BackgroundColor="Gray" WidthRequest="120" HeightRequest="180">
          <Label Text="3" TextColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
      </StackLayout>
      <StackLayout BackgroundColor="Gray" WidthRequest="120" HeightRequest="180">
          <Label Text="4" TextColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
      </StackLayout>
    </suave:DynamicWrapLayout>
</ScrollView>

Features

  • Bindable child views
  • Bindable to collections
  • Handles layout changing well (try rotating the device)
  • Doesn’t require custom renderers (All Xamarin.Forms baby!)

What does this thing look like?

Android:


iOS:


Notes

This does not use any native view virtualization, which means performance does not scale well with extremely large data sets.

Coming soon

  • ItemSelected event and SelectedItem bindable property (for now, you can add custom gestures and commands to your DataTemplate and handle the events yourself)
     

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Borderless Inputs

I published multiple posts this week about creating Xamarin.Forms controls without borders using Custom renderers. This post is your one stop shop for all these posts. These are the controls that are used in my repository to create Material Design inputs in Xamarin.Forms that you can find here:
https://github.com/SuavePirate/SuaveControls.MaterialFormControls. These will be talked about in posts to come!
Check the borderless controls out here:

  1. Xamarin.Forms Borderless Entry
  2. Xamarin.Forms Borderless Picker
  3. Xamarin.Forms Borderless DatePicker
  4. Xamarin.Forms Borderless TimePicker
  5. Xamarin.Forms Borderless Editor

And check out how they look here:

BorderlessEntry


BorderlessEditor

BorderlessPicker

BorderlessDatePicker

BorderlessTimePicker

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Mvvm Light and Dependency Injection

Inversion of Control and Dependency Injection are some design principles that help make our applications more flexible and scalable. They both help us separate our implementations and make it easy to substitute drastic changes to our implemented data or business logic whether it be for writing unit tests or product improvement.

Xamarin is a platform where IoC and DI fit extremely well. I’ve talked about this concept a few other times in both my blogs and videos about the Onion Architecture in Xamarin as well as how to call Platform Specific code from a Portable Class Library. You can find those posts and videos here:

  1. Onionizing Xamarin Part 6
  2. [VIDEO] Xamarin.Tips: Calling Platform-Specific Code from a PCL (Dependency Injection)

In this post, I want to talk about using DI with Mvvm Light at a VERY basic level.

First, let’s define an interface for a service we might use:

IUserService.cs

public interface IUserService
{
    Task<User> GetCurrentUserAsync();
}

Now let’s create two different implementations. One that will be the service used in the application and the other that will be used for testing.

UserService.cs

public class UserService : IUserService
{
    // makes a call to a web api to get a user
    public async Task<User> GetCurrentUserAsync()
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetAsync("https://mywebapi.mydomain/api/currentuser");
            var content = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<User>(content);
        }
    }
}

TestUserServices.cs

public class TestUserService : IUserService
{
    public Task<User> GetCurrentUserAsync()
    {
        return Task.FromResult(new User { Name = "Test User" });
    }
}

Now we need a ViewModel that will use this service. We define a private readonly IUserService and then inject the implementation that we want in the constructor of the ViewModel.

CurrentUserViewModel.cs

public class CurrentUserViewModel : ViewModelBase
{
    // use the interface as the service and inject the implementation in the constructur
    private readonly IUserService _userService;
    private User _user;

    public User User
    {
        get
        {
            return _user;
        }
        set
        {
            Set(ref _user, value);
        }
    }

    public CurrentUserViewModel(IUserService userService)
    {
        _userService = userService;
    }

    public async Task UpdateUserAsync()
    {
        User = await _userService.GetCurrentUserAsync();
    }
}

Now let’s define an IoCConfig that handles registering dependencies and implementations.

IoCConfig.cs

public class IoCConfig
{
    public IoCConfig()
    {
        // use SimpleIoc from MvvmLight as our locator provider
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    }

    // register the real implementation
    public void RegisterServices()
    {
        SimpleIoc.Default.Register<IUserService, UserService>();
    }

    // register the test implementation
    public void RegisterTestServices()
    {
        SimpleIoc.Default.Register<IUserService, TestUserService>();
    }

    // register the view model
    public void RegisterViewModels()
    {
        SimpleIoc.Default.Register<CurrentUserViewModel>();
    }
}

Now that we can register our Services as well as our ViewModels, the dependency resolver from SimpleIoc can retrieve an instance of CurrentUserViewModel with whichever version of IUserService is registered depending on whether we call RegisterServices or RegisterTestServices.

Now we can retrieve our instance of the CurrentUserViewModel by calling

var currentUserViewModel = ServiceLocator.Current.GetInstance<CurrentUserViewModel>();

MvvmLight recommends using a ViewModelLocator to get the instance of your ViewModels:

ViewModelLocator.cs

public class ViewModelLocator
{
    private readonly IoCConfig _iocConfig;
    public CurrentUserViewModel CurrentUser
    {
        get
        {
            return ServiceLocator.Current.GetInstance<CurrentUserViewModel>();
        }
    }

    public ViewModelLocator()
    {
        _iocConfig = new IoCConfig();
        _iocConfig.RegisterServices();
        //_iocConfig.RegisterTestServices();
        _iocConfig.RegisterViewModels();
    }

}

It’s recommended to either create your ViewModelLocator at the app start up, or if you’re using Xamarin.Forms, register it as a Resource in your App.xaml

<Application ...     xmlns:locator="clr-namespace:YOUR_LOCATOR_LOCATION">
    <Application.Resources>
        <ResourceDictionary>
            <locator:ViewModelLocator x:Key="Locator"/>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Now in your XAML pages, you can automatically wire up your view model.

MainPage.xaml

<ContentPage ...     BindingContext="{Binding Source={StaticResource Locator}, Path=CurrentUser}"     Title="{Binding User.Name}">
...
</ContentPage>

In order to change to your testing data, you can just switch which call to your IoCConfig is made for registering your dependency without having to make any changes to any of your other layers or UI!

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Adding Dynamic Elevation to Your Xamarin.Forms Buttons

Before Reading

In a previous post, I talked about bringing Material Design to your iOS applications in Xamarin.Forms and adding drop shadows to them. You might want to read that here first: Xamarin.Tips – Creating a Material Design Button in iOS

In another post, we learned how to override the Android Button Elevations. We will be doing this in this post in order to set a dynamic elevation. You can read that here: Xamarin.Tips – Overriding Android Button Shadows/Elevation

Now in this post, we will combine these two concepts with a new custom Xamarin.Forms component called MaterialButton that will have a new Elevation property to control the elevation and shadow of the underlying button control.

The source code and an example can be found here: https://github.com/SuavePirate/MaterialButton

Using the existing code

You can of course use the code I wrote and put on GitHub for this. In order to use it, simply:

  1. Clone the repository at  https://github.com/SuavePirate/MaterialButton
  2. Include all 3 `src` projects in your Solution
  3. Reference the Shared project in all Xamarin.Forms and platform projects
  4. Reference the Android project in your Android projects
  5. Reference the iOS project in your iOS projects
  6. Use the control as below (see example projects to demo)

Reference the control in your XAML:

MainPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"              xmlns:local="clr-namespace:MaterialButtonExample"              xmlns:suave="clr-namespace:SuaveControls.MaterialButton.Shared;assembly=SuaveControls.MaterialButton.Shared"              x:Class="MaterialButtonExample.MainPage">

	<suave:MaterialButton x:Name="MyButton"                            BackgroundColor="#03A9F4"                            TextColor="White"                            Text="Click to raise elevation"                            Elevation="1"                            VerticalOptions="Center"                            HorizontalOptions="Center"                           WidthRequest="300"                           Clicked="MyButton_Clicked"/>

</ContentPage>

MainPage.xaml.cs

namespace MaterialButtonExample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void MyButton_Clicked(object sender, EventArgs e)
        {
            MyButton.Elevation++;
        }
    }
}

In your iOS AppDelegate you’ll also need to call the Initialize method to ensure that the Custom renderer does not get excluded during linking:

AppDelegate.cs

namespace MaterialButtonExample.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            MaterialButtonRenderer.Initialize();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

Now you can see your results!

Creating Your Own Material Design Button

First things first, let’s create our new Xamarin.Forms control before we implement our custom renderers:

MaterialButton.cs

namespace SuaveControls.MaterialButton.Shared
{
    public class MaterialButton : Button
    {
        public static BindableProperty ElevationProperty = BindableProperty.Create(nameof(Elevation), typeof(float), typeof(MaterialButton), 4.0f);

        public float Elevation
        {
            get
            {
                return (float)GetValue(ElevationProperty);
            }
            set
            {
                SetValue(ElevationProperty, value);
            }
        }
    }
}

Now let’s implement our iOS and Android custom renderers.

iOS:
MaterialButtonRenderer


[assembly: ExportRenderer(typeof(MaterialButton), typeof(MaterialButtonRenderer))]
namespace SuaveControls.MaterialButton.iOS
{
    public class MaterialButtonRenderer : ButtonRenderer
    {
        public static void Initialize()
        {
            // empty, but used for beating the linker
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
                return;

        }

        public override void Draw(CGRect rect)
        {
            base.Draw(rect);
            UpdateShadow();
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if(e.PropertyName == "Elevation")
            {
                UpdateShadow();
            }
        }

        private void UpdateShadow()
        {

            var materialButton = (Shared.MaterialButton)Element;

            // Update shadow to match better material design standards of elevation
            Layer.ShadowRadius = materialButton.Elevation;
            Layer.ShadowColor = UIColor.Gray.CGColor;
            Layer.ShadowOffset = new CGSize(2, 2);
            Layer.ShadowOpacity = 0.80f;
            Layer.ShadowPath = UIBezierPath.FromRect(Layer.Bounds).CGPath;
            Layer.MasksToBounds = false;

        }
    }
}

Notice how we use the UpdateShadow method to use the Elevation property to set the ShadowRadius of our UIButton's Layer.

It’s important to also make the UpdateShadow call in the OnElementPropertyChanged so that we can dynamically change the Elevation property in our Xamarin.Forms control and see it reflected in the underlying UIButton.

Now let’s do it on Android:

MaterialButtonRenderer

[assembly: ExportRenderer(typeof(MaterialButton), typeof(MaterialButtonRenderer))]
namespace SuaveControls.MaterialButton.Droid
{
    public class MaterialButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
    {
        ///
<summary>
        /// Set up the elevation from load
        /// </summary>

        /// <param name="e"></param>
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement == null)
                return;

            var materialButton = (Shared.MaterialButton)Element;

            // we need to reset the StateListAnimator to override the setting of Elevation on touch down and release.
            Control.StateListAnimator = new Android.Animation.StateListAnimator();

            // set the elevation manually
            ViewCompat.SetElevation(this, materialButton.Elevation);
            ViewCompat.SetElevation(Control, materialButton.Elevation);
        }

        public override void Draw(Canvas canvas)
        {
            var materialButton = (Shared.MaterialButton)Element;
            Control.Elevation = materialButton.Elevation;
            base.Draw(canvas);
        }

        ///
<summary>
        /// Update the elevation when updated from Xamarin.Forms
        /// </summary>

        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if(e.PropertyName == "Elevation")
            {
                var materialButton = (Shared.MaterialButton)Element;
                ViewCompat.SetElevation(this, materialButton.Elevation);
                ViewCompat.SetElevation(Control, materialButton.Elevation);
                UpdateLayout();
            }
        }
    }
}

Just as mentioned in the iOS implementation, we need to make sure that we implement our changes in both the OnElementChanged method as well as the OnElementPropertyChanged event to ensure we are able to update our Elevation with MVVM.

Now we can use our control in our pages!

MainPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"              xmlns:local="clr-namespace:MaterialButtonExample"              xmlns:suave="clr-namespace:SuaveControls.MaterialButton.Shared;assembly=SuaveControls.MaterialButton.Shared"              x:Class="MaterialButtonExample.MainPage">

	<suave:MaterialButton x:Name="MyButton"                            BackgroundColor="#03A9F4"                            TextColor="White"                            Text="Click to raise elevation"                            Elevation="1"                            VerticalOptions="Center"                            HorizontalOptions="Center"                           WidthRequest="300"                           Clicked="MyButton_Clicked"/>

</ContentPage>

MainPage.xaml.cs

namespace MaterialButtonExample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void MyButton_Clicked(object sender, EventArgs e)
        {
            MyButton.Elevation++;
        }
    }
}

In your iOS AppDelegate you’ll also need to call the Initialize method to ensure that the Custom renderer does not get excluded during linking:

AppDelegate.cs

namespace MaterialButtonExample.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            MaterialButtonRenderer.Initialize();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

Now you can see your results!

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – MvvmLight Code Snippets for Visual Studio for Mac

I previously made a post about some Mvvm Light shortcuts / code snippets in Visual Studio, but what about Visual Studio for Mac?

Code snippets in Visual Studio for Mac work a little differently, but here is how to add your own:

  1. Go to Visual Studio > Preferences > Text Editor > Code Snippets
  2. Click on the Add button
  3. Set the language for your snippet, the shortcut, and other optional options
  4. Write the template for your snippet
  5. Confirm and use

Here are two easy ones that have made my life easier for a Bindable Property and Relay Command:

propb:

private $type$ $fieldName$;

public $type$ $name$
{
    get
    {
        return $fieldName$;
    }
    set
    {
        Set(() => $name$, ref $fieldName$, value);
    }
}

Screen Shot 2017-05-25 at 4.38.45 PM

rcmd:

private ICommand $fieldName$;

public ICommand $name$ => $fieldName$ ??
    ($fieldName$ = new RelayCommand(() => ));

Screen Shot 2017-05-25 at 4.39.19 PM.png

It’s as easy as that. Now go out there and start writing less code!

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Xamarin.Tip – Binding a Picker to an Enum

So a recent Xamarin.Forms update released the new Bindable Picker, which allows you to bind an IList of objects to the picker (which will be ToString()‘ed). However, I’ve often find myself needing to create a form for a model that has enum properties. Previously, in order to do this, I would have to create a custom List or string from my enum and map it manually, then read from the SelectedItem bound to another string property, then when I need the actual value I’d have to map it back to the enum it “represents”.

It might have looked something like this:

MyViewModel.cs

...
private DogBreed _breedEnum; // this is our enum of: BorderCollie, LabradorRetriever, PitBull, etc.

public List<string> BreedNames
{
    get
    {
        return new List<string> { "Border Collie", "Labrador Retriever", "Pit Bull" };
    }
}

private string _selectedBreed;
public string SelectedBreed
{
    get
    {
        return _selectedBreed;
    }
    set
    {
        Set(ref _selectedBreed, value); // this is using MvvmLight
    }
}

public void DoSomethingWithTheBreed()
{
    switch(SelectedBreed)
    {
        case "Border Collie": _breedEnum = DogBreed.BorderCollie;
            break;
        case "Labrador Retriever": _breedEnum = DogBreed.LabradorRetriever;
            break;
        case "Pit Bull": _breedEnum = DogBreed.PitBull;
            break;
        //...
    }

    DoSomething(_breedEnum);
}
...

And our XAML

<Picker ItemsSource="{Binding BreedNames}" SelectedItem="{Binding SelectedBreed}"/>

As you can see, this is pretty gross…

Here’s a quick little strategy I use to make the binding process a little easier with my enums. It’s broken into just 3 quick parts:

  1. Create a extension methods to get a readable string from our `enum`
  2. Create a `Converter` to convert the `SelectedIndex` to the `enum` field
  3. Wire up the fields and XAML

Let’s create our enum extension methods to get a readable string for the UI:
StringExtensions.cs

    public static class StringExtensions
    {
        public static string SplitCamelCase(this string str)
        {
            return Regex.Replace(
                Regex.Replace(
                    str,
                    @"(\P{Ll})(\P{Ll}\p{Ll})",
                    "$1 $2"
                ),
                @"(\p{Ll})(\P{Ll})",
                "$1 $2"
            );
        }
    }

This SplitCamelCase method will take a string that is camel cased and split it out into separate words such as `”ThisIsMyValue”.SplitCamelCase(); // “This Is My Value”

Now that we have the ability to get a readable string from the enum values, let’s create our ViewModel properties we will need.

MyViewModel.cs

...
private DogBreed _selectedBreed;
public DogBreed SelectedBreed
{
    get
    {
        return _selectedBreed;
    }
    set
    {
        Set(ref _selectedBreed, value);
    }
}

public List<string> BreedNames
{
    get
    {
        return Enum.GetNames(typeof(DogBreed)).Select(b => b.SplitCamelCase()).ToList();
    }
}

public void DoSomethingWithBreed()
{
    DoSomething(SelectedBreed);
}
...

So much cleaner already. Now we need to create a Converter that our XAML can use to actually set the SelectedBreed property of our ViewModel.

IntEnumConverter.cs

    public class IntEnumConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is Enum)
            {
                return (int)value;
            }
            return 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value is int)
            {
                return Enum.ToObject(targetType, value);
            }
            return 0;
        }
    }

Last thing to do is use our IntEnumConverter and our properties to create our view in XAML:

MyView.xaml

<ContentPage.Resources>
    <ResourceDictionary>
        <converters:IntEnumConverter x:Key="IntEnum"/>
    </ResourceDictionary>
</ContentPage.Resources>
<Picker ItemsSource="{Binding BreedNames}" SelectedIndex="{Binding SelectedBreed, Converter=IntEnum}"/>

Here’s what we have!

Now you have the means to bind any of your Pickers quite easily to any of your custom enum fields!

“Woah! How did you get that Material Design Looking Picker on iOS”… Stay tuned!

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.