Monday, April 03, 2017

Displaying a Xamarin.Forms ActionSheet using MVVM

When it comes to mobile applications, there are many different ways to prompt a user for input. Xamarin.Forms has adopted a technique originally introduced in iOS called an ActionSheet that can prompt the user for one or many options.

While Xamarin.iOS provides the UIAlertController to display Popups and ActionSheets, the only way to present the ActionSheet in Xamarin.Forms is through the DisplayActionSheet method on the Page object. If we want to present this dialog to our users using MVVM, accessing the Page object from the code-behind would be violating one of the MVVM best-practices, so we’d need to find another way that’s more “MVVM Friendly”. I’ve had a lot of success with the following approach. Maybe you will, too.

What’s an ActionSheet?

Before we dive into the MVVM component, let’s take a closer look at the ActionSheet. An ActionSheet prompts the user to choose a selection from a list but also provides two specific options: Cancel and Destruction.  The “Cancel” option is obvious, but perhaps the “Destruction” option may not. In iOS, this term represents a destructive operation that is highlighted in red. For example, an actionsheet shown to users during a photo editing session may show a list of file sizes (“Small”, “Medium”, “Large”), a “Cancel” button and a destructive operation, “Discard Changes”.

Options, Options, Options…

To show the ActionSheet using bindings from our ViewModel, we have a few options:

  1. Implement a custom control. We could implement a custom control to house our logic to launch the ActionSheet, but this feels a bit awkward, especially since it wouldn’t actually render anything. We’d also run into issues about where to put the Control in the logical tree.
  2. Custom Behaviour. This seems like the best approach, but the way behaviours are implemented in Xamarin.Forms isn’t exactly how they’re done in WPF, and I discovered first hand a few issues where bindings were being fired multiple times, etc. Which led me to…
  3. Attached Properties. Perhaps the precursor to Behaviors, Attached Properties provide us with a mechanism to store state in the visual elements and then define callbacks for when those values change. This technique isn’t as clean as I’d like but it works really well.

Show me the Codes

As mentioned above, my preferred approach to show the ActionSheet works on this basic principle:

  • Bind some data that we want to show using some Attached Properties,
  • Trigger the ActionSheet when one of the BindableProperty changes,
  • Use the VisualTreeHelper mentioned in my last post to find the Page element,
  • Display the ActionSheet using the Page.DisplayActionSheet method.

We’ll expose the following properties:

  • Parameters: rather than binding all the various display values as separate values, we bundle them up into a single class (see ActionSheetParameters below)
  • IsVisible: the BindableProperty that will be used to trigger the alert.
  • Result: the BindableProperty that will contain the user’s selection.
  • ResultCommand: an alternative to using the Result property if you want to be notified by Command when the user selects a value.

The end result looks like this:


namespace XF.CaliburnMicro1.Controls
{
    using System.Windows.Input;
    using Xamarin.Forms;

    public class ActionSheet
    {
        #region Parameters
        public static BindableProperty ParametersProperty =
            BindableProperty.CreateAttached(
                "Parameters", 
                typeof(ActionSheetParameters), 
                typeof(ActionSheet), 
                default(ActionSheetParameters));

        public static ActionSheetParameters GetParameters(BindableObject bindable)
        {
            return (ActionSheetParameters)bindable.GetValue(ParametersProperty);
        }

        public static void SetParameters(BindableObject bindable, ActionSheetParameters value)
        {
            bindable.SetValue(ParametersProperty, value);
        }
        #endregion

        #region Result
        public static BindableProperty ResultProperty =
            BindableProperty.CreateAttached(
                "Result", 
                typeof(string), 
                typeof(ActionSheet), 
                default(string), 
                defaultBindingMode: BindingMode.TwoWay);

        public static string GetResult(BindableObject bindable)
        {
            return (string)bindable.GetValue(ResultProperty);
        }

        public static void SetResult(BindableObject bindable, string value)
        {
            bindable.SetValue(ResultProperty, value);
        }
        #endregion

        #region Command
        public static BindableProperty CommandProperty =
            BindableProperty.CreateAttached(
                "Command",
                typeof(ICommand),
                typeof(ActionSheet),
                null);

        public static ICommand GetCommand(BindableObject bindable)
        {
            return (ICommand)bindable.GetValue(CommandProperty);
        }

        public static void SetCommand(BindableObject bindable, string value)
        {
            bindable.SetValue(CommandProperty, value);
        } 
        #endregion

        #region IsVisible
        public static BindableProperty IsVisibleProperty =
           BindableProperty.CreateAttached(
               "IsVisible", 
               typeof(bool), 
               typeof(ActionSheet), 
               default(bool), 
               propertyChanged: OnShowDialog, 
               defaultBindingMode: BindingMode.TwoWay);

        public static bool GetIsVisible(BindableObject bindable)
        {
            return (bool)bindable.GetValue(IsVisibleProperty);
        }

        public static void SetIsVisible(BindableObject bindable, bool value)
        {
            bindable.SetValue(IsVisibleProperty, value);
        }
        #endregion

        private static async void OnShowDialog(BindableObject bindable, object oldValue, object newValue)
        {
            bool showAlert = (bool)newValue;
            if (showAlert)
            {
                var page = VisualTreeHelper.GetParent<Page>((Element)bindable);

                ActionSheetParameters args = GetParameters(bindable);
                
                if (page != null && args != null)
                {
                    string result = await page.DisplayActionSheet(args.Title, args.Cancel, args.Destruction, args.Buttons);

                    SetResult(bindable, result); // pass result back to binding

                    // pas result back to viewmodel using command
                    ICommand command = GetCommand(bindable);
                    if (result != null && command != null)
                    {
                        command.Execute(result);
                    }

                    SetIsVisible(bindable, false); // reset the dialog
                }
            }
        }
    }

    public class ActionSheetParameters
    {
        /// <summary>
        /// Action sheet title
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// Cancel button title
        /// </summary>
        public string Cancel { get; set; }

        /// <summary>
        /// Destructive action title
        /// </summary>
        public string Destruction { get; set; }

        /// <summary>
        /// List of Buttons
        /// </summary>
        public string[] Buttons { get; set; }
    }
}

From the above, the work is done when the IsVisible property changes. Our ViewModel would look like this:

public class ExampleViewModel : Screen
{
    private bool _showDialog;
    private string _result;
    private ActionSheetParameters _parameters;

    public ExampleViewModel()
    {
        ShowDialogCommand = new DelegateCommand((o) =>
        {
            DialogParameters = new ActionSheetParameters
            {
                Title = "Choose your option wisely",
                Cancel = "Cancel",
                Destruction = "Self Destruct",
                Buttons = new[] { "One", "Two", "Red", "Blue" }
            };

            ShowDialog = true;
        });
    }

    public bool ShowDialog
    {
        get { return _showDialog; }
        set { SetField(ref _showDialog, value); }
    }

    public string Result
    {
        get { return _result; }
        set { SetField(ref _result, value); }
    }

    public ActionSheetParameters DialogParameters
    {
        get { return _parameters; }
        set { SetField(ref _parameters, value); }
    }

    public DelegateCommand ShowDialogCommand
    {
        get;
        protected set;
    }

    protected void SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (!Object.Equals(field, value))
        {
            field = value;
            NotifyOfPropertyChange(propertyName);
        }
    }
}

And the corresponding View:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:XF.CaliburnMicro1.Controls"
             x:Class="XF.CaliburnMicro1.Views.Tab2View"
             
             controls:ActionSheet.Parameters="{Binding DialogParameters}"
             controls:ActionSheet.Result="{Binding Result}"
             controls:ActionSheet.IsVisible="{Binding ShowDialog}"
             >

    <StackLayout>
        <Button Text="Show Dialog" Command="{Binding ShowDialogCommand}" />
        <Label Text="{Binding Result}" />
    </StackLayout>    
    
</ContentView>

This technique works well for both iOS and Android.

Happy coding.

submit to reddit

Sunday, March 26, 2017

VisualTreeHelper for Xamarin.Forms

I enjoy working with Xamarin.Forms because it allows me to leverage my XAML background for cross-platform technologies. While Xamarin.Forms has come a long way over the last few years, there are a few gaps between WPF/Modern Apps and the Xamarin implementation of XAML.

One of those gaps is the VisualTreeHelper that ships as part of WPF. The VisualTreeHelper is especially useful when developing custom controls, Attached Properties or Behaviors. For example, an Attached Property like Grid.Row can search up the visual tree to find the parent Grid control.

While there is no implementation within Xamarin.Forms, there are some examples that offer partial solutions.

The class hierarchy for Xamarin.Forms gives us a bit of insight about the visual tree. A controls and visual elements share a common base class, Element.

Xamarin.Forms-ElementHierarchy

Here’s my implementation for GetParent<T> and GetChildren<T>:

public static class VisualTreeHelper
{
    public static T GetParent<T>(this Element element) where T : Element
    {
        if (element is T)
        {
            return element as T;
        }
        else
        {
            if (element.Parent != null)
            {
                return element.Parent.GetParent<T>();
            }

            return default(T);
        }
    }
        
    public static IEnumerable<T> GetChildren<T>(this Element element) where T : Element
    {
        var properties = element.GetType().GetRuntimeProperties();

        // try to parse the Content property
        var contentProperty = properties.FirstOrDefault(w => w.Name == "Content");
        if (contentProperty != null)
        {
            var content = contentProperty.GetValue(element) as Element;
            if (content != null)
            {
                if (content is T)
                {
                    yield return content as T;
                }
                foreach (var child in content.GetChildren<T>())
                {
                    yield return child;
                }
            }
        }
        else
        {
            // try to parse the Children property
            var childrenProperty = properties.FirstOrDefault(w => w.Name == "Children");
            if (childrenProperty != null)
            {
                // loop through children
                IEnumerable children = childrenProperty.GetValue(element) as IEnumerable;
                foreach (var child in children)
                {
                    var childVisualElement = child as Element;
                    if (childVisualElement != null)
                    {
                        // return match
                        if (childVisualElement is T)
                        {
                            yield return childVisualElement as T;
                        }

                        // return recursive results of children
                        foreach (var childVisual in childVisualElement.GetChildren<T>())
                        {
                            yield return childVisual;
                        }
                    }
                }
            } 
        }
    }
}

As the VisualTreeHelper is implemented as a static class, it can be used stand-alone or as extension methods on an object:

// from within user control...

Page page = null;
StackLayout stack = this.FindByName<StackLayout>("myStack");

// utility class
page = VisualTreeHelper.GetParent<Page>(stack);

// using extension method
page = stack.GetParent<Page>();

Well, that's it for now. My next post will show how a practical example.

Happy coding.

Monday, March 13, 2017

Applying MVVM to Xamarin.Form’s TabbedPage (Updated)

My last post showed how to setup a TabbedPage with separate View/ViewModels for each tab using Caliburn.Micro. The post used a DataTemplateSelector to resolve the tab content which isn’t the preferred technique when working with Caliburn.Micro. Today we’ll use a strategy that is more aligned to Caliburn’s philosophy and is a tiny bit more extensible.

As per the previous post, we used a DataTemplateSelector because the default TabbedPage.ItemTemplate expects a ContentPage and we wanted to use existing ContentPage items as tabs. In reality, this was a situation that occurred because our team had originally developed these pages independently and then wanted to consolidate them into a TabbedPage after the fact. If you don’t plan on navigating to these pages outside of the TabbedPage, we can build up our ContentPage inside the DataTemplate and use Caliburn.Micro’s binding syntax. This approach will require us to change our existing ContentPage(s) into ContentView(s) and since we depended on the Page objects to provide us with Title and Icon information, we’ll need to push this information into our ViewModels.

Modify ViewModels

Let’s introduce a simple interface for our ViewModels that will be tabs in our TabbedPage:


public interface ITabViewModel
{
   string Title { get; }
   string Icon { get; }
   int SortOrder { get; }
}

The changes to the ViewModel are pretty trivial. We simply implement the ITabViewModel interface:


public class Tab1ViewModel : Screen, ITabViewModel
{
   public Tab1ViewModel()
   {
      Tab1Content = "Tab 1 Content";
   }

   public string Tab1Content { get; set; }

   public string Icon => "Tab1.png";

   public int SortOrder => 0;

   public string Title => "Tab1";
}

public class Tab2ViewModel : Screen, ITabViewModel
{
   public Tab2ViewModel()
   {
      Tab2Content = "Tab 2 Content";
   }

   public string Tab2Content { get; set; }

   public string Icon => "Tab2.png";

   public int SortOrder => 0;

   public string Title => "Tab 2";
}

Next, we register our ViewModels in the App using the ITabViewModel signature:


public class App : FormsApplication
{
   private readonly SimpleContainer container;

   public App(SimpleContainer container)
   {
      this.container = container;

      // TODO: Register additional viewmodels and services
      container
         .PerRequest<Main2ViewModel>()
         .PerRequest<ITabViewModel,Tab1ViewModel>()
         .PerRequest<ITabViewModel,Tab2ViewModel>()
         ;

      Initialize();

      DisplayRootViewFor<Main2ViewModel>();
   }
 
   // snip...
}

Lastly, we can change our Screen Conductor to be less coupled to the specific ViewModels:


public class Main2ViewModel : Conductor<Screen>.Collection.OneActive
{
   public Main2ViewModel(IEnumerable<ITabViewModel> tabs)
   {
      if (tabs.Any())
      {
         foreach(var tab in tabs.OrderBy(i => i.SortOrder))
         {
            Items.Add((Screen)tab);
         }

         ActivateItem(Items[0]);
      }
   }
}

Modify Views

The changes to the view are also very trivial. We’re simply changing them from ContentPage to ContentView. There are a few attributes that aren’t available (Title, Icon) so we’ll simply remove them if present.
And then finally, we can remove our DataTemplateSelector and use the View.Model attached property to resolve our ContentView:

Main2View.xaml

<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" 
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
            xmlns:cm="clr-namespace:Caliburn.Micro.Xamarin.Forms;assembly=Caliburn.Micro.Platform.Xamarin.Forms"
            x:Class="XF.CaliburnMicro1.Views.Main2View"
            ItemsSource="{Binding Items}"
            SelectedItem="{Binding ActiveItem}"
            >
    <TabbedPage.ItemTemplate>
        <DataTemplate>
            <ContentPage Title="{Binding Title}" Icon="{Binding Icon}">
                <ContentView cm:View.Model="{Binding}" />
            </ContentPage>
        </DataTemplate>
    </TabbedPage.ItemTemplate>
</TabbedPage>

Easy peasy.

Happy coding.

submit to reddit

Sunday, March 05, 2017

Applying MVVM to Xamarin.Forms's TabbedPage

For this post I thought we'd dig into an example that came up recently with Caliburn.Micro and the TabbedPage view, specifically how to apply MVVM using Caliburn.Micro.

The TabbedPage view that ships with Xamarin.Forms is a great cross-platform page structure that presents sets of content in different tabs. The layout is surprisingly very similar between iOS, Android and Windows 10. The biggest layout difference is seen in iOS where each tab optionally has an icon.

xamarinforms_tabbedpage

The above image, taken without permission from Xamarin’s documentation, shows iOS, Android and Windows 8.1 Phone. The Windows 10 version is closer to the Android version.

When looking at Xamarin’s documentation, most examples show a series of Pages defined as inline XAML, and applying an ItemTemplate assumes that each tab will have the same layout; there doesn’t seem to be a great way to swap in different pages per tab. Regardless of these short-comings, the most important point regarding these examples is that the TabbedPage view displays the the Title and Icon from the contained Page in the tab headers.

Setting up the ViewModel

The first step in setting up a TabbedPage view is to represent it as its own ViewModel. Caliburn.Micro offers a unique solution to this problem using a pattern it refers to as a Screen Conductor. To understand how this pattern works, Caliburn.Micro treats pages of your application as Screens and the base Screen class contains abstractions for the view lifecycle: OnInitialize, OnActivated, OnDeactivated. These methods, respectively, make it really easy to defer work that shouldn’t be in the constructor, to ensure the view always has the latest data, and to clean-up or prevent navigating away without saving changes. With regards to the TabbedPage, the ScreenConductor provides a simple mechanism to activate and deactivate ViewModels as you navigate between tabs.

Here we define our ScreenConductor as our Main2ViewModel, and Tab1ViewModel and Tab2ViewModel as the contained tabs.

namespace XF.CaliburnMicro1.ViewModels
{
    using Caliburn.Micro;

    public class Main2ViewModel : Conductor<Screen>.Collection.OneActive
    {
        public Main2ViewModel(Tab1ViewModel tab1, Tab2ViewModel tab2)
        {
            Items.Add(tab1);
            Items.Add(tab2);

            ActivateItem(Items[0]);
        }
    }

    public class Tab1ViewModel : Screen
    {
        public Tab1ViewModel()
        {
            DisplayName = "Tab 1";
            Tab1Content = "Tab 1 Content";
        }

        public string Tab1Content { get; set; }
    }

    public class Tab2ViewModel : Screen
    {
        public Tab2ViewModel()
        {
            DisplayName = "Tab 2";
            Tab2Content = "Tab 2 Content";
        }

        public string Tab2Content { get; set; }
    }
}

For completeness sake, these new ViewModels are registered in the App class (defined in my previous post):

public class App : FormsApplication
{
   private readonly SimpleContainer container;

   public App(SimpleContainer container)
   {
       this.container = container;

       // TODO: Register additional viewmodels and services
       container
          .PerRequest<Main2ViewModel>()
          .PerRequest<Tab1ViewModel>()
          .PerRequest<Tab2ViewModel>()
          ;

       Initialize();

       DisplayRootViewFor<Main2ViewModel>();
    }

    // snip...
}

The XAML definitions for these views are represented as a TabbedPage and two instances of ContentPage:

Main2View.xaml
<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" 
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
            xmlns:converters="clr-namespace:XF.CaliburnMicro1.Converters"
            x:Class="XF.CaliburnMicro1.Views.Main2View"
            ItemsSource="{Binding Items}"
            SelectedItem="{Binding SelectedItem}"
            >

</TabbedPage>
Tab1View.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"
             x:Class="XF.CaliburnMicro1.Views.Tab1View"
             Title="{Binding DisplayName}">
  <Label Text="{Binding Tab1Content}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>
Tab2View.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"
             x:Class="XF.CaliburnMicro1.Views.Tab2View"
             Title="{Binding DisplayName}">
  <Label Text="{Binding Tab2Content}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

Fixing View / ViewModels for Tabs

If you run the solution as is, you’ll be disappointed. The reason for this is that while Caliburn.Micro can find the View/ViewModel for our MainPage, it doesn’t know how to resolve the View/ViewModels for the tabs. Now the solution I’m going to use leverages a DataTemplateSelector which isn’t something that is traditionally done with Caliburn.Micro. The correct approach with Caliburn.Micro is to take advantage of conventions and special attached properties (eg View.Model). However in this case, the approach I’m using allows you to use your ContentPage inside the TabbedPage or as a standalone page that you can navigate to directly. I’ll cover the other approach in an upcoming post.

We’ll define a DataTemplateSelector that can do the work of finding the View for our ViewModel:

namespace XF.CaliburnMicro1.Converters
{
    using System;
    using System.Collections.Generic;
    using Caliburn.Micro;
    using Caliburn.Micro.Xamarin.Forms;
    using Xamarin.Forms;    

    public class TabbedPageDataTemplateSelector : DataTemplateSelector
    {
        private readonly Dictionary<Type, DataTemplate> _selectors;

        public TabbedPageDataTemplateSelector()
        {
            _selectors = new Dictionary<Type, DataTemplate>();
        }

        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            Type viewModelType = item.GetType();

            DataTemplate template = null;

            // check if we've already found the datatemplate for this view
            if (!_selectors.TryGetValue(viewModelType, out template))
            {
                // use caliburn to find the View for this viewmodel
                Type viewType = ViewLocator.LocateTypeForModelType(viewModelType, null, null);

                template = new DataTemplate(() =>
                {
                    var view = Activator.CreateInstance(viewType);

                    var bindableObject = view as BindableObject;

                    if (bindableObject != null)
                    {
                        // when the view's content changes...
                        bindableObject.BindingContextChanged += (sender, args) =>
                        {
                            var page = sender as Page;

                            // leverage a caliburn view lifecyle event
                            // if the viewmodel supports it
                            var viewAware = page?.BindingContext as IViewAware;
                            viewAware?.AttachView(page);
                        };
                    }

                    return view;
                });

                // cache the datatemplate
                _selectors.Add(viewModelType, template);
            }

            // return the correct view for the viewmodel
            return template;
        }
    }
}

Then associate into the view:

<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" 
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
            xmlns:converters="clr-namespace:XF.CaliburnMicro1.Converters"
            x:Class="XF.CaliburnMicro1.Views.Main2View"
            ItemsSource="{Binding Items}"
            SelectedItem="{Binding SelectedItem}"
            >
    <TabbedPage.ItemTemplate>
        <converters:TabbedPageDataTemplateSelector />
    </TabbedPage.ItemTemplate>
</TabbedPage>

Now when we run our solution, our tabs are correctly populated.

tabbedpage-content

Happy coding!

submit to reddit

Monday, February 20, 2017

Configuring Xamarin.Forms.UWP to use Caliburn Micro

Update 2017/10/15: This walk through is now available as a Visual Studio Template! More details here: https://marketplace.visualstudio.com/items?itemName=BryanBCook.XamarinFormsCaliburnMicroStarterKit

This is the fourth post in this series where we’re configuring a Xamarin.Forms application to use my favourite MVVM framework, Caliburn.Micro. Today’s post will focus on configuring a Universal Windows Application (UWP).

Here’s links to the previous posts:

  1. Getting Started with Xamarin.Forms and Caliburn.Micro
  2. Configuring Xamarin.Forms.Droid to use Caliburn.Micro
  3. Configuring Xamarin.Forms.iOS to use Caliburn.Micro

If you’ve ever built a WPF application, it may seem strange that we’re not going to build XAML pages for our app. Instead, we’re going to leverage the XAML defined in our PCL so that we can reuse as much of the user-interface logic as possible. The pages that we’re adding here act purely as an entry point into our Xamarin.Forms application.

Change App.xaml

Caliburn provides a base application class that we’re going to extend. In our App.xaml, we’ll change the root element to CaliburnApplication, like so:

<cm:CaliburnApplication
    x:Class="XF.CaliburnMicro1.UWP.App"
    xmlns:cm="using:Caliburn.Micro"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    RequestedTheme="Light">
    
</cm:CaliburnApplication>

Configure IoC Container

Next we’ll add the plumbing logic that we’ve added to the other applications to initialize our platform-specific IoC container. Caliburn.Micro has a customized container for UWP, called WinRTContainer, that contains a few helpful registration methods.

I’ve replaced the default App.xaml.cs with this simplified version:

namespace XF.CaliburnMicro1.UWP
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using Windows.ApplicationModel.Activation;
    
    using Caliburn.Micro;
    
    using XF.CaliburnMicro1.ViewModels;

    sealed partial class App
    {
        private WinRTContainer _container;

        public App()
        {
            InitializeComponent();
        }

        protected override void Configure()
        {
            _container = new WinRTContainer();
            _container.RegisterWinRTServices();

            _container.Singleton<XF.CaliburnMicro1.App>();
        }

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
                return;

            Xamarin.Forms.Forms.Init(args);

            // loads our MainPage as the root frame
            DisplayRootView<MainPage>();
        }

        #region IoC Overrides
        protected override void BuildUp(object instance)
        {
            _container.BuildUp(instance);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _container.GetAllInstances(service);
        }

        protected override object GetInstance(Type service, string key)
        {
            return _container.GetInstance(service, key);
        }

        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            return new[]
            {
                GetType().GetTypeInfo().Assembly,
                typeof(MainViewModel).GetTypeInfo().Assembly
            };
        } 
        #endregion
    }
}

Eventually, you’ll want to provide additional logic for initialization and suspension specific to UWP, but for now OnLaunched simply launches MainPage as the root window for our Xamarin.Forms app.

Customize MainPage

The Xamarin.Forms template includes a MainPage that is optimized for Xamarin.Forms, we simply need to load our App from the Singleton defined in Caliburn’s IoC Container.

namespace XF.CaliburnMicro1.UWP
{
    using Caliburn.Micro;

    public sealed partial class MainPage
    {
        public MainPage()
        {
            this.InitializeComponent();

            LoadApplication(IoC.Get<XF.CaliburnMicro1.App>());
        }
    }
}

Build and Run

Finally, before we give our UWP a spin, we need to make a minor change the deployment to the Solution.

  1. Change the start-up application to XF.CaliburnMicro.UWP (Universal Windows) and set the target platform to Any CPU
  2. Open the Configuration Manager for the solution

    uwp_configuration
  3. Specify that the solution should Deploy for Debug configuration

    image
  4. Specify Local machine as the target Device
  5. Compile and Run (F5)

You should now see our familiar View / ViewModel from the PCL should be displayed.

Windows 10:

image

Windows 10 Mobile:

image

Next Steps

We’re now set to handle iOS, Android and Universal Windows Apps using Caliburn.Micro, so that’s all for this series. Follow my Xamarin.Forms label to see more posts in this space.

Until then… Happy Coding.

submit to reddit

Configure Xamarin.Forms iOS to use Caliburn.Micro

Update 2017/10/15: This walk through is now available as a Visual Studio Template! More details here: https://marketplace.visualstudio.com/items?itemName=BryanBCook.XamarinFormsCaliburnMicroStarterKit

We’re continuing with our series of getting started with Xamarin.Forms and Caliburn.Micro, check out these previous posts if you’re interested:

Today, we’ll set up our Xamarin.Forms iOS project. Unlike the Droid project, we can get our project up and running with very few changes to the default template. So we'll start this post with configuring our Visual Studio instance to talk to our Mac.

And before you ask, unfortunately, although it's C# you absolutely need a Mac to compile and run the solution. On the plus side, you can do most of your development on your PC.

Verify Prerequisite Software on your Mac

You will need the following installed on your Mac:

  • XCode 7+
  • Xamarin Studio
  • Xamarin.iOS SDK

Setup your Mac for Remote Access

Before you can configure Visual Studio to use your Mac as a Build Host, you'll need to configure your Mac to allow users to remotely login to your machine. You can get the full details following this post, but in short we can simply set up our mac using the following:

  • Press Command ⌘ + Space to bring up Spotlight Search
  • Type Remote Login to open Sharing
  • Enable Remote Login and then specify Allow access for: All Users 

Configure your Build Host

Now that your Mac will accept remote logins, we can now configure Visual Studio on the PC to use your Mac as a build host.

  • From your PC, open our XF.CaliburnMicro project.
  • In the toolbar, click on the Xamarin Mac Agent icon (also Tools –> iOS –> Xamarin Mac Agent):

    mac_agent_toolbar

  • If your mac is running, it should appear in the dialog:

    image

  • Select your Mac, click Connect…
  • You’ll be prompted to login, so provide the credentials you use when logging into the Mac
  • Once connected, the toolbar changes colour and provides the option to launch the simulator:

    mac_agent_connected_toolbar

Note this assumes that both the Mac and the PC are on the same network and that all required software is installed and configured for use.

Create and configure IoC Container

Now that we have our environment dependencies out of the way, we can turn our attention to modifying the template code to leverage Caliburn.Micro.

Similar to our Droid project, we need to set up our IoC container. For iOS, we do this by using a CaliburnAppDelegate which looks almost identical to the Application class we created for Android.

namespace XF.CaliburnMicro1.iOS
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    
    using Caliburn.Micro;
    
    using XF.CaliburnMicro1.ViewModels;

    class CaliburnAppDelegate : CaliburnApplicationDelegate
    {
        private SimpleContainer _container;

        public CaliburnAppDelegate()
        {
            Initialize();
        }

        protected override void Configure()
        {
            _container = new SimpleContainer();
            _container.Instance(_container);

            _container.Singleton<App>();

            // TODO: Register all platform services here
        }

        protected override void BuildUp(object instance)
        {
            _container.BuildUp(instance);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _container.GetAllInstances(service);
        }

        protected override object GetInstance(Type service, string key)
        {
            return _container.GetInstance(service, key);
        }

        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            return new[]
            {
                GetType().Assembly,
                typeof(MainViewModel).Assembly
            };
        }
    }
}

We then modify the AppDelegate to leverage our CaliburnAppDelegate, and change the start-up routine to use our App singleton.

namespace XF.CaliburnMicro1.iOS
{
    using Foundation;
    using UIKit;
    
    using Caliburn.Micro;
    using Xamarin.Forms.Platform.iOS;

    [Register("AppDelegate")]
    public partial class AppDelegate : FormsApplicationDelegate
    {
        private readonly CaliburnAppDelegate appDelegate = new CaliburnAppDelegate();

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

            LoadApplication(IoC.Get<App>());

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

Build and Run

To run your application, you’ll need to change the start project, select a target and the Device. Here I’ve selected XF.CaliburnMicro.iOS project, specified the iPhoneSimulator target and the iPhone 6s iOS 10.x simulator.

build_and_run

If everything worked, you should now see our Xamarin.Forms app backed by our Caliburn.Micro ViewModel.

Next Steps

So there you go! We’ve got both Android and iOS projects running. Our next post we’ll continue down this path and our Xamarin.Forms project to leverage the Universal Windows Platform which will target tablets, phones and PCs.

submit to reddit

Sunday, February 05, 2017

Configure Xamarin.Forms Droid to use Caliburn.Micro

Update 2017/10/15: This walk through is now available as a Visual Studio Template! More details here: https://marketplace.visualstudio.com/items?itemName=BryanBCook.XamarinFormsCaliburnMicroStarterKit

In my last post, we created a Xamarin.Forms project and added necessary components for taking advantage of my favourite MVVM framework, Caliburn.Micro. However, the solution didn't compile because we needed to make some platform specific changes. Today we'll address this.

Add an Application

The main entry point into our Android application is the Application class as defined in the AndroidManifest.xml. By default, the Xamarin.Forms template does not include an Application class, but we’ll need one in order to hold some global state.

To register our custom application, we subclass Caliburn’s CaliburnApplication class and mark it with an [Application] attribute:

namespace XF.CaliburnMicro1.Droid
{
    using System;
    using Android.App;
    using Android.Runtime;
    using Caliburn.Micro;

    [Application]
    public class Application : CaliburnApplication
    {
        public Application(IntPtr javaReference, JniHandleOwnership transfer)
              : base(javaReference, transfer)
        {
        }

        public override void OnCreate()
        {
            base.OnCreate();

            Initialize();
        }
    }
}

Create and configure IoC

One of the main features of the CaliburnApplication is to create our platform-specific Inversion of Control (IoC) container and register any platform-specific abstractions.

There are four primary methods that we need to implement in our Application (SelectAssemblies, BuildUp, GetAllInstances, GetInstance). These methods are the backing implementation for Caliburn's IoC:

It's important to note that we register the Xamarin.Forms App as a singleton before we activate it. This is largely because we want the App to have the same lifetime as our Android Application, which avoids a few scenarios where the Android application lifecycle causes the App class to be reinitialized more than once.

Our Application class now looks like this:

namespace XF.CaliburnMicro1.Droid
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    
    using Android.App;
    using Android.Runtime;
    
    using Caliburn.Micro;
    
    using XF.CaliburnMicro1.ViewModels;

    [Application]
    public class Application : CaliburnApplication
    {
        private SimpleContainer _container;

        public Application(IntPtr javaReference, JniHandleOwnership transfer)
              : base(javaReference, transfer)
        {
        }

        public override void OnCreate()
        {
            base.OnCreate();

            Initialize();
        }

        protected override void Configure()
        {
            _container = new SimpleContainer();

            // make the container available for resolution
            _container.Instance(_container);

            // CRITICAL! make sure our Xamarin.Forms App 
            // can only be initilized once!
            _container.Singleton<App>();

            // TODO: Register any Platform-Specific abstractions here
        }

        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            // Get a list of all assemblies that will be used
            // by the IoC container
            return new[]
            {
                GetType().Assembly,
                typeof (MainViewModel).Assembly
            };
        }

        protected override void BuildUp(object instance)
        {
            _container.BuildUp(instance);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _container.GetAllInstances(service);
        }

        protected override object GetInstance(Type service, string key)
        {
            return _container.GetInstance(service, key);
        }
    }
}

Modify MainActivity

The last modification we need to make is a slight change to our existing MainActivity. Rather than instantiating our App class, we resolve it from the IoC container.

namespace XF.CaliburnMicro1.Droid
{
    using Android.App;
    using Android.Content.PM;
    using Android.OS;
    
    using Xamarin.Forms.Platform.Android;
    
    using Caliburn.Micro;

    [Activity(
        Label = "XF.CaliburnMicro1", 
        Icon = "@drawable/icon", 
        MainLauncher = true, 
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : FormsApplicationActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

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

            // Resolve the App class to use the singleton we created
            LoadApplication(IoC.Get<App>());
        }
    }
}

Compile and Run

At this point, the android project should be good to go. Set the project as the default target, and run (F5). The project should automatically be configured to deploy the app to the emulator.

Next Steps

So we have our Android application running our Caliburn.Micro flavoured Xamarin.Forms app. The next step is to configure our iOS project with similar customizations.

submit to reddit

Saturday, February 04, 2017

Getting Started with Xamarin.Forms and Caliburn.Micro

Update 2017/10/15: This walk through is now available as a Visual Studio Template! More details here: https://marketplace.visualstudio.com/items?itemName=BryanBCook.XamarinFormsCaliburnMicroStarterKit

Let me say this: Xamarin.Forms is awesome.

Xamarin.Forms is a great way to build native iOS and Android applications using C# and XAML. But if you’re just starting out, you’ll find that the most of the documentation out there, including Charles Petzold’s fantastic book, are lacking great examples on how to do MVVM, which is XAMLs strongest feature.

Last year when Caliburn.Micro finally released version 3.0 with support with Xamarin.Forms I was disappointed that there wasn’t much documentation to support it as well.

So with that said, lets build a Xamarin.Forms app using Caliburn.Micro.

Create Project

Good news here is that Visual Studio will do most of the work for us. To create a blank Xamarin.Forms project, choose File –> New Project. Then select the template Visual C# –> Cross Platform –> Blank App (Xamarin.Forms Portable).

image

If you specify the project name XF.CaliburnMicro, Visual Studio will create several projects:

  • XF.CaliburnMicro (Portable) – This is the PCL library that will hold our Views and ViewModels and core services and interfaces
  • XF.CaliburnMicro.Droid – Our Android application
  • XF.CaliburnMicro.iOS – Our iPhone / iPad application
  • XF.CaliburnMicro.UWP (Universal Windows) – Our Windows 10 desktop/tablet/mobile application.
  • XF.CaliburnMicro.Windows (Windows 8.1) – A Windows 8.1 app, for those of us that didn’t take the free upgrade.
  • XF.CaliburnMicro.WinPhone (Windows Phone 8.1) – A Windows Phone 8.1 Silverlight/XAML application.

Note: You’ll likely be prompted to specify a Windows 10 version. For now, don’t worry about this, just click OK.

Also note that I’m only going to focus on Android, iOS and UWP, so feel free to delete XF.CaliburnMicro.Windows and XF.Caliburn.WinPhone.

Compile and Run

Now would be a good time to make sure everything compiles and your machine is good to go. Xamarin.Forms requires a few dependencies to get up and running, so before we start messing things up this would be a good time for a sanity test.

For simplicity sake, let’s focus only on getting our Android emulator running. If you’re able to see the default Forms page, we’re good.

Moving along…

Reference NuGet Packages

It’s time to add Caliburn.Micro to the project. There are three key NuGet packages we’re interested in:

  • Caliburn.Micro
  • Caliburn.Micro.Core
  • Caliburn.Micro.XamarinForms

What seems a bit counter intuitive is that the Caliburn.Micro package is platform specific, so it cannot be referenced by the PCL library.

The best way to add these to your project is to right-click the solution and choose Manage NuGet Packages for Solution. Search for “Caliburn.Micro.XamarinForms” and add it to all projects. It’ll bring in the Caliburn.Micro.Core dependency.

Search for “Caliburn.Micro.Core” and add it to the PCL “XF.CaliburnMicro (Portable)” project.

Setup basic View and ViewModel

Caliburn uses conventions to automatically map Views to ViewModels and vice-versa, so you’ll need to create two folders Views and ViewModels in the XF.XamarinForms (Portable) project.

The ViewModels\MainViewModel is pretty straight forward:

using Caliburn.Micro;
using System.Runtime.CompilerServices;

namespace XF.CaliburnMicro1.ViewModels
{
    public class MainViewModel : Screen
    {
        private string _mainText;

        public MainViewModel()
        {
           MainText = "Hello World!";
        }         

        public string MainText
        {
            get { return _mainText; }
            set
            {
                SetField(ref _mainText, value);
            }
        }

        protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            if (!object.Equals(field, value))
            {
                field = value;
                NotifyOfPropertyChange(propertyName);
                return true;
            }
            return false;
        }
    }
}

And the Views\MainView.xaml is an empty screen created using Project –> Add New Item –> Forms Xaml Page:

<?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="XF.CaliburnMicro1.Views.MainView">
  <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

Introduce Caliburn.Micro

If you’ve worked with Caliburn.Micro in the past, you would normally configure a Bootstrapper as the primary entry point for the application. In Xamarin.Forms, the closest equivalent is the App class that is created in the PCL project. We’ll use it to setup our Inversion of Control (IoC) container and register ViewModels, services and abstractions.

Caliburn.Micro ships with a simple IoC container, aptly named SimpleContainer, which offers simple functionality to register and resolve dependencies. It is possible to replace this container with a different one if you prefer, but in my experience the SimpleContainer does exactly what we need.

namespace XF.CaliburnMicro1
{
    using Caliburn.Micro;
    using Caliburn.Micro.Xamarin.Forms;
    using Xamarin.Forms;
    using XF.CaliburnMicro1.ViewModels;

    public class App : FormsApplication
    {
        private readonly SimpleContainer container;

        public App(SimpleContainer container)
        {
            this.container = container;

            // TODO: Register additional viewmodels and services
            container
                .PerRequest<MainViewModel>();

            Initialize();

            DisplayRootViewFor<MainViewModel>();
        }

        protected override void PrepareViewFirst(NavigationPage navigationPage)
        {
            container.Instance<INavigationService>(new NavigationPageAdapter(navigationPage));
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

Next Steps

At this point, the solution doesn’t compile, and that’s because we’ve changed the signature of the App class and we’ll have to adjust our iOS, Android and UWP projects to suit. Admittedly, it’s an awkward place to stop a blog post, but there’s a lot more to cover. Over the next few blog posts, we’ll setup the platform specific projects with their Caliburn parts and we’ll update the links below.

submit to reddit

Saturday, January 21, 2017

This time on a mac

There’s been less activity than normal around here. Looking back, I missed last year completely. That’s more than a blip, that’s a complete year. Not sure what happened, I think it was a perfect storm...

Those that know me know that I started practicing Karate in 2015 and my facebook feed has been filled with belt exams and karate videos. I’m highly motivated to obtain my first degree in under three years, so three times a week in evening classes and weekends makes it difficult to find a few extra cycles to experiment and blog. On the plus side, I’m probably the most fit I’ve ever been, I've dropped nearly twenty pounds, toned up and dangerous.

The other major shift for me was professionally work wasn’t selling the projects that suited my skills. I kinda had a crisis of faith of sorts, where I felt I had to choose a new religion. I switched into managing more people, bought a mac and learned Swift, and explored leveraging my .net and WPF strengths in Xamarin. Work would eventually pick up later in the year, but in true agency fashion it involved dusting off my Unity3D skills, learning how to rock a HoloLens and learn Python and Ruby while I was at it. There’s loads to blog about it.

I want to touch on the macbook reference above. I feel like I’ve made a career out of bashing apple. (I ended many arguments in the 90s with apple fanboys with my favourite argument killer: “...but it’s a mac…”) Buying a mac for me was huge slice of humble pie. I still use a PC at work, but my mac is now my playground and go to device when I want to do something that isn’t “work”. I’m writing this on a mac, trying out blogo today.

One last thing, to accompany my macbook I switched to an iPhone and parted ways with my Windows Phone. I’m no stranger to iOS as I’ve had an iPad and iPhone in the past, but I was on Windows Phone for years with three different devices. I loved the platform, and still do, but I got tired of waiting for apps that the rest of the planet had. Apply Pay and wallet are awesome. I may still buy a lumina to play with UWP with Xamarin.

So what should you expect this year around here? Well, hopefully I can make good on promises to blog more, but expect to see a combination of development and agile delivery practices. You’ll likely see some Xamarin, some UI automation, maybe a HoloLens. From an agile delivery perspective, expect some tips and tricks to bring to your team as well as a focus on DevOps and Test Automation.

Friday, December 04, 2015

List of C# Compiler Warnings

Generally, you want to fix compiler warnings as they come up, but you may need to suppress some of them for legitimate reasons. A list of warnings and errors can be found here, but there’s no high-level list.
Here is a summarized list of warnings.

 

Warning Description More Info

Level 1 Warnings (Severe)

CS0420 ‘identifier’: a reference to a volatile field will not be treated as volatile https://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx
CS0465 Introducing a ‘Finalize’ method can interfere with destructor invocation. https://msdn.microsoft.com/en-us/library/02wtfwbt.aspx
CS1058 A previous catch clause already catches all exceptions https://msdn.microsoft.com/en-us/library/ms228623.aspx
CS1060 Use of possibly unassigned field 'name'. Struct instance variables are initially unassigned if struct is unassigned. https://msdn.microsoft.com/en-us/library/bb384216.aspx
CS1598 XML parser could not be loaded for the following reason: 'reason'. The XML documentation file 'file' will not be generated. https://msdn.microsoft.com/en-us/library/szfbfb7e.aspx
CS1607 A warning was generated from the assembly-creation phase of the compilation. https://msdn.microsoft.com/en-us/library/4a0640cd.aspx
CS1616 Option 'option' overrides attribute 'attribute' given in a source file or added module https://msdn.microsoft.com/en-us/library/0b104xt8.aspx
CS1658 'warning text'. See also error 'error code'
The compiler emits this warning when it overrides an error with a warning.
https://msdn.microsoft.com/en-US/library/ft0k10fs.aspx
CS1683 Reference to type 'Type Name' claims it is defined in this assembly, but it is not defined in source or any added modules https://msdn.microsoft.com/en-US/library/6b351z64.aspx
CS1685 The predefined type 'System.type name' is defined in multiple assemblies in the global alias; using definition from 'File Name' https://msdn.microsoft.com/en-us/library/8xys0hxk.aspx
CS1690 Accessing a member on 'member' may cause a runtime exception because it is a field of a marshal-by-reference class https://msdn.microsoft.com/en-us/library/x524dkh4.aspx
CS1691 'number' is not a valid warning number https://msdn.microsoft.com/en-us/library/7z6tx3wa.aspx
CS1699 Use command line option "compiler_option" or appropriate project settings instead of "attribute_name" https://msdn.microsoft.com/en-us/library/xh3fc3x0.aspx
CS1762 A reference was created to embedded interop assembly '<assembly1>' because of an indirect reference to that assembly from assembly '<assembly2>'. Consider changing the 'Embed Interop Types' property on either assembly. https://msdn.microsoft.com/en-us/library/ff183282.aspx
CS1956 Member 'name' implements interface member 'name' in type 'type'. There are multiple matches for the interface member at run-time. It is implementation dependent which method will be called. https://msdn.microsoft.com/en-us/library/bb882526.aspx
CS3003 Type of 'variable' is not CLS-compliant https://msdn.microsoft.com/en-us/library/ax5w23a6.aspx
CS3007 Overloaded method 'method' differing only by unnamed array types is not CLS-compliant https://msdn.microsoft.com/en-us/library/3w1d36e0.aspx
CS3009 'type': base type 'type' is not CLS-compliant https://msdn.microsoft.com/en-us/library/tdd79w48.aspx
CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. https://msdn.microsoft.com/en-us/library/hh873131.aspx

Level 2 Warnings

CS0108 'member1' hides inherited member 'member2'. Use the new keyword if hiding was intended. https://msdn.microsoft.com/en-US/library/3s8070fc.aspx
CS0467 Inherited members from different interfaces that have the same signature cause an ambiguity error. https://msdn.microsoft.com/en-us/library/ms228509.aspx
CS0618 'member' is obsolete: 'text' https://msdn.microsoft.com/en-us/library/x5ye6x1e.aspx
CS1701 Assuming assembly reference "Assembly Name #1" matches "Assembly Name #2", you may need to supply runtime policy https://msdn.microsoft.com/en-us/library/2h4x8b08.aspx

Level 3 Warnings (Less Severe)

CS0675 Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first https://msdn.microsoft.com/en-us/library/wdc6717a.aspx
CS1700 Assembly reference Assembly Name is invalid and cannot be resolved https://msdn.microsoft.com/en-us/library/ac36c25f.aspx

Level 4 Warnings (Informational)

CS0429 Unreachable expression code detected https://msdn.microsoft.com/en-us/library/2ch1a3w5.aspx
CS1591 Missing XML comment for publicly visible type or member 'Type_or_Member' https://msdn.microsoft.com/en-us/library/zk18c1w9.aspx
CS1610 Unable to delete temporary file 'file' used for default Win32 resource -- resource https://msdn.microsoft.com/en-US/library/z4aytccf.aspx

submit to reddit

Tuesday, November 17, 2015

Configure SourceTree to Rebase by default

Here’s a quick tip for Git for Windows users that are using Atlassian’s SourceTree as their visual interface.

If you’re using git flow as a branching strategy, a good habit to form is to use git pull --rebase when you update your local branch. This technique updates your local branch and then “replays” your changes on top, effectively putting your changes at the head of the branch.

The SourceTree Pull dialog supports this feature with a checkbox, but it’s not enabled by default.

image

To make this checkbox selected by default:

  1. Tools –> Options
  2. Git
  3. Check the “use rebase instead of merge by default for tracked branches” option

image

Friday, October 09, 2015

Init Methods are Crap

This title of this post pretty much sums up how I feel about Init methods. Let’s take a look at an example why.

I’ve been on a soap-box yelling at anyone who’ll listen that “work in the constructor” is perhaps the worst thing you can do as a developer. You’ve drank the cool-aid and you have some fairly important initialization logic that needs to be called, so you move the logic out of the constructor and into a separate method. Your code now looks like this:

public class MenuProvider : IMenuProvider
{
    private Array<MenuItem> _menuItems;
    
    public void Initialize()
    {
        // do work to populate menu items, serialize from file, etc...
        _menuItems = // some value;
    }

    public IEnumerable<MenuItem> MenuItems
    {
        get
        {
            return _menuItems;
        }
    }

    public IEnumerable<MenuItem> InActiveMenuItems
    {
        get
        {
	    return _menuItems.Where(i => i.Active == false);
        }
    }

}

It's a contrived example, but in the above code MenuItems will be null and InActiveMenuItems throws an error unless you call Initialize() first. Certainly, there must be a better design than this? (If you answered put the work in the constructor, please come see me after class, I.. uh,.. have something for you.)

Putting the onus on the developer to call methods in a certain order is a very backward approach. You, the class designer, should make it difficult for people to do things the wrong way. We can take on some of that onerous effort inside the class, something like this should work nicely:

public class MenuProvider : IMenuProvider
{
   private bool _isInitialized;
   private object _lock = new object();
   private Array<MenuItem> _menuItems;

   public IEnumerable<MenuItem> GetMenuItems()
   {
        EnsureInitialized();
    
        return _menuItems;
   }

   public IEnumerable<MenuItem> GetInactiveMenuItems()
   {
        EnsureInitialized();

        return _menuItems.Where(i => i.Active == false);
   }

   private void EnsureInitialized()
   {
        if (!_initialized)
        {
            Initialize();
        }
   }
   
   private void Initialize()
   {
        lock(_lock)
        {
            if (!_initialized)
            {
                // do initialization work
                _initialized = true;
            }
        }
   }
}

In this design, I've made a few minor adjustments. For stylistic purposes, I converted the properties into methods because properties look awkward on interfaces. Properties also aren't a good choice if there's work involved in calculating them, so methods feel better here.

Outside of the cosmetic changes, one of the most notable changes is that my Initialize method is now private. I've also added some plumbing logic to ensure that the Initialize method only does work the first time it's called, and since this is good defensive programming, this might have already existed and shouldn't be a surprise.

What should stand out to you, is that each method is responsible for ensuring that the initialization logic is called on the user's behalf using the EnsureInitialized method before doing any other work. Some developers may grumble that this seems like a simple thing to forget when adding new methods and thus has potential for silly bugs. That’s fair, but because the API for the class has been simplified the tests to catch this should be much easier to write and find.

Alternatively, we can take this approach further by splitting the concerns into smaller parts. One part could read the file contents and the other part could be responsible for serving the data to consumers. This is effectively just moving the Initialize method to another class. Something like this:

public class MenuProvider : IMenuProvider
{
    private MenuReader _reader;

    public MenuProvider(MenuReader reader)
    {
        _reader = reader;
    }

    public IEnumerable<MenuItem> GetMenuItems()
    {
        return _reader.GetAll();
    }

    public IEnumerable<MenuItem> GetInactiveMenuItems()
    {
        return _reader.GetAll().Where(i => i.Active == false);
    }
}

public abstract class MenuReader
{
    public abstract IEnumerable<MenuItem> GetAll();
}

public class StaticFileMenuReader : MenuReader
{
    private Array<MenuItem> _items;

    public IEnumerable<MenuItem> GetAll()
    {
        if (_items != null)
        {
            // do serialization work
        }
        return _items;
    }
}

This small change greatly simplifies the MenuProvider and the extra step to move the serialization logic into another class may seem familiar to others as a Repository pattern. The repository pattern in this example also affords us additional test flexibility as the file-system can be abstracted away with a test-double.

To sum up, it seems a bit odd to design a class that requires methods to be called in a specific order. Initialization in general is something that the class designer should be well equipped to handle, so don’t push this responsibility to others – a few small changes to your class makes your code more usable, responsive and easier to test.

submit to reddit

Wednesday, October 07, 2015

MEF Hacks: Constructors with parameters

Often, there’s a need to register an object into your dependency container that takes constructor arguments. There are a few ways to accomplish this with MEF.

You’re mileage will vary, but my favorite approach is a bit of a hack that leverages a lesser-known feature of MEF: Property Exports.

public class ComplexObjectExportFactory
{
    [Export]
    public MyComplexObject ComplexObject
    {
        get
        {
            return new MyComplexObject("config.xml");
        }
    }
}

This "simply works" and doesn't require you to do anything intrusive like sub-classing a dependency or registering named parameters on application start-up. The technique is especially useful if you need to provide any kind of conditional logic based on settings and it can even build upon other MEF registered parts, for example:

internal class ComplexObjectExportFactory
{
    private readonly IApplicationSettingsProvider _settings;
    private readonly IEventAggregator _eventAggregator;

    [ImportingConstructor]
    public ComplexObjectExportFactory(
            IApplicationSettingsProvider settings, 
            IEventAggregator eventAggregator)
    {
        _settings = settings;
        _eventAggregatore = eventAggregator;
    }

    [Export]
    public MyComplexObject ComplexObject
    {
        get
        {
            string configFile = _settings.GetSetting("ComplexObjectConfigFile");
            int timeout = _settings.GetSetting<int>("ComplexObjectTimeoutSeconds");
            
            return new MyComplexObject(_eventAggregator, configFile, timeout);
        }
    }
}

The only real down-fall to this overall approach is that the ComplexObjectExportFactory will never have any usages, so tools like Resharper will think this is dead-code, but this can be solved with a few well placed #pragmas and some comments. The other reason this feels like a hack, and this is more of an esthetics or stylistic difference, is that this feels like it should be a method (eg, factory.Create()) but MEF treats exported methods very differently.

Despite the awkwardness of this class, I’d prefer this to sub-classing third-party dependencies or bloating the bootstrapper with additional initialization logic. Maybe you think so too?

Happy coding.

submit to reddit

Monday, October 05, 2015

Application Services for WPF Applications

Suppose you’re building a WPF application and have a number of actions that you want to perform on application start-up. Here’s a pattern that I’ve used successfully for the last few years that works with Caliburn.Micro or other MVVM frameworks…

If you're using Caliburn.Micro, the framework provides a Bootstrapper as an entry point to your application and the overridable Configure method is a great place to initialize your application-specific services.

You might be tempted to do something like this:

protected override void Configure()
{
    Container = new CompositionContainer(
       new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

    var batch = new CompositionBatch();

    // initialize Caliburn.Micro services and register with container
    EventAggregator = new EventAggregator();

    batch.AddExportedValue<IWindowManager>(new WindowManager());
    batch.AddExportedValue<IEventAggregator>(EventAggregator);
    batch.AddExportedValue(Container);
    Container.Compose(batch);

    // initialize and register all my custom components
    var myService = new MyService();
    myService.Configure("config.xml");
    // repeat for all other services...

}

While this strategy works for one or two services, you'll find that as you add additional services your Bootstrapper logic becomes quite bloated and simply owns too many responsibilities.

To simplify things, let's define a simple interface that describes all of our application services:

public interface IApplicationService : IDispose
{
    void Initialize();
}

And now we can generically initialize all services that implement this interface:

protected void Configure()
{
   // snip...
   Container.Compose(batch);

   InitializeApplicationServices();
}

protected void InitializeApplicationServices()
{
   var services = Container.GetExports<IApplicationService>();
   foreach (Lazy<IApplicationService> exportedService in services)
   {
       IApplicationService service = exportedService.Value;
       Log.InfoFormat("Initializing IApplicationService:{0}.", service.GetType().Name);
       service.Initialize();
   }
}

protected override OnExit(object sender, EventArgs e)
{
    Container.Dispose();

    base.OnExit(sender, e);
}

[Export(typeof(IApplicationService))]
public class MyApplicationService : IApplicationService
{
    private MyService _service;        

    public void Initialize()
    {
       _service = new MyService();
       _service.Configure("config.xml"); 
    }

    public void Dispose()
    {
       GC.SuppressFinialize(this);
       Dispose(true);
    }
    protected virtual void Dispose(bool disposing)
    {
       _service.Dispose();       
    }
}

There! That’s a lot cleaner. Now the Bootstrapper doesn’t know anything about our services and we can add new services without having to further extend this class. There are a few additional benefits:

  1. If you’re using MEF, all classes that are export IApplicationService are singletons by default.
  2. All services have a predefined start (Initialize) and end (Dispose), thereby avoiding work that is often put in the constructor.
  3. Perhaps not obvious, but if you’re using MEF, calling Container.Dispose() when the application exits automatically calls Dispose on all our application services, too.

So there you have a basic initialization routine for all your background services. My next few posts will demonstrate how to really take advantage of this pattern.

P.S: Astute readers of my blog might recognize that I'm using an Initialize() method which I've called out as a bad habit on my On Notice Board. While “Init methods” is high on my list, the context here is different. In this context, the only method I know about is Initialize(), whereas the “Init method” smell is a required method that must be called before calling other methods on the same class. I’ll blog about how to remove Init methods later.

submit to reddit

Sunday, June 14, 2015

Debugging Google Authentication + Azure MobileServices

Let’s say you’re building a mobile application using Azure MobileServices with Google Authentication but you want to debug and run the solution on your local developer environment. This post will walk you through setting up your local environment and provide an example of how to test your local services.

Before we start, the getting started documentation on how to add Google Authentication to your mobile application is pretty good, and if you follow the samples it’s fairly easy to get up and running. For the purposes of this post, I’m not going to repeat those setup instructions so if you’re trying to get it running you should definitely read this article before reading any further. I should also point out that I’m using a .NET Backend for my MobileService, so there are a few minor variances if you’re using Node.

Step 1: add your Google Client ID and Client Secret to your web.config. By default, the configuration for your MobileService is defined through the Azure MobileServices dashboard so local values in your web.config are ignored in the Azure environment. In order to debug Google Authentication locally, simply provide values for MS_GoogleClientID, MS_GoogleClientSecret in your web.config:

Google_Auth_WebConfig

Step 2: modify the settings of your Google Project to support your local environment. At this point, attempts to authenticate in your local environment will fail because the Redirect Url for your local environment doesn’t match the settings defined in the Google Developer Console. Fortunately, the good folks at Google had the smarts to allow multiple redirect URLs. Simply provide the URL of your local developer environment. In my case, I’m running this in IIS Express and I’m using the URL http://localhost:61915

  1. Navigate to https://console.developers.google.com/project and select your Project
  2. In the Credentials section, click the Edit Settings button and add your local URL to the Authorized Redirect URIs.

Google_Auth_WebConfig_RedirectUri

Testing it out

So we’ve made a few simple changes and now it’s time to test it out.

  1. Navigate to http://localhost:61915/login/google in your browser.
  2. If all things are properly configured you should be redirected to Google’s oAuth page to provide consent to your application. Provide consent, dummy.
  3. Your browser will be redirected to a special URL (http://localhost:61915/done#token=<json-data>).
  4. Copy the URL and decode it. I like to use this online tool http://meyerweb.com/eric/tools/dencoder/
  5. Once decoded, make note of the authentication-token.

Google_Auth_RedirectUri_Decoded

  1. Now using your favourite REST client (mine's the Chrome Advanced REST Client), supply the header X-ZUMO-AUTH: + your auth token and call any web-API method that would require authentication.

Cheers!

submit to reddit