DEV Community

PeterMilovcik
PeterMilovcik

Posted on • Updated on

Setup & Use Autofac in Xamarin.Forms

What is Autofac?

According to https://autofac.org/:
Autofac is an addictive Inversion of Control container for .NET Core, ASP.NET Core, .NET 4.5.1+, Universal Windows apps, and more.

Here are some simple steps to setup Autofac in Xamarin.Forms.

Let me know if you found it useful.

Once, you have created a new Xamarin.Forms project with Shell template continue with the following steps:

Manage NuGet Packages for the Xamarin.Forms library

  • Select the Browse tab and search for Autofac (Author(s): Autofac Contributors)
  • Get the latest stable version and select Install
  • Commit

Bootstrap

  • Add new folder Bootstrap in Xamarin.Forms library
  • Create new class AppContainer in this new Bootstrap folder
  • Add using Autofac;
  • Implement an AppContainer class. This example shows how to register types for the builder as single instances. Use your types, of course.
  • Commit
  • If you add or change the view models, don't forget to adapt AppContainier class accordingly.
public class AppContainer
    {
        private static IContainer container;

        public AppContainer()
        {
            // services
            var builder = new ContainerBuilder();
            builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();
            builder.RegisterType<DialogService>().As<IDialogService>().SingleInstance();
            builder.RegisterType<RepositoryService>().As<IRepositoryService>().SingleInstance();
            builder.RegisterType<PreferenceService>().As<IPreferenceService>().SingleInstance();

            // view models
            builder.RegisterType<MainViewModel>().SingleInstance();
            builder.RegisterType<ActivitiesViewModel>().SingleInstance();
            builder.RegisterType<ActivityRecordViewModel>().SingleInstance();
            builder.RegisterType<HistoryViewModel>().SingleInstance();

            container = builder.Build();
        }

        public T Resolve<T>() => container.Resolve<T>();

        public object Resolve(Type type) => container.Resolve(type);
    }
Enter fullscreen mode Exit fullscreen mode

How to implement ViewModelLocator

ViewModelLocator is a class that creates ViewModel classes and wires them together with View classes:

  • Wiring is based on the naming convention where Views are located in .Views. namespace, ViewModels ends with suffix ViewModel and Views are named with suffix View (e.g., ItemsView, ItemsViewModel).
  • AutoWireViewModelProperty is used to enable this auto wiring for the View.
  • Make sure that your View XAML files and classes are renamed accordingly. (ItemsPage to ItemsView).
  • Register ViewModel type in the AppContainer class (e.g., ItemsViewModel)

Here is an example implementation:

public static class ViewModelLocator
    {
        private static readonly AppContainer Container;

        static ViewModelLocator() => Container = new AppContainer();

        public static readonly BindableProperty AutoWireViewModelProperty =
            BindableProperty.CreateAttached(
                "AutoWireViewModel",
                typeof(bool),
                typeof(ViewModelLocator),
                default(bool),
                propertyChanged: OnAutoWireViewModelChanged);

        public static bool GetAutoWireViewModel(BindableObject bindable) =>
            (bool)bindable.GetValue(AutoWireViewModelProperty);

        public static void SetAutoWireViewModel(BindableObject bindable, bool value) =>
            bindable.SetValue(AutoWireViewModelProperty, value);

        public static T Resolve<T>() where T : class => Container.Resolve<T>();

        private static async void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
        {
            if (!(bindable is Element view))
            {
                return;
            }

            var viewType = view.GetType();
            var viewName = viewType.FullName.Replace(".Views.", ".ViewModels.");
            var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
            var viewModelName = $"{viewName}Model, {viewAssemblyName}";

            var viewModelType = Type.GetType(viewModelName);
            if (viewModelType != null)
            {
                var viewModel = Container.Resolve(viewModelType) as ViewModel;
                if (viewModel != null)
                {
                    await viewModel.Initialize(null);
                }
                view.BindingContext = viewModel;
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Enable AutoWire in View

xmlns:vm="clr-namespace:YourNamespace.ViewModels;assembly=YourAssembly"

vm:ViewModelLocator.AutoWireViewModel="True"

Other handy classes:

ViewModel base class

    public class ViewModel : Observable
    {
        public ViewModel()
        {
            NavigationService = ViewModelLocator.Resolve<INavigationService>();
            DialogService = ViewModelLocator.Resolve<IDialogService>();
            RepositoryService = ViewModelLocator.Resolve<IRepositoryService>();
            PreferenceService = ViewModelLocator.Resolve<IPreferenceService>();
        }

        protected INavigationService NavigationService { get; }
        protected IDialogService DialogService { get; }
        protected IRepositoryService RepositoryService { get; }
        protected IPreferenceService PreferenceService { get; }

        public virtual Task Initialize(object parameter) => Task.CompletedTask;
        public virtual Task Initialize() => Initialize(null);
    }
Enter fullscreen mode Exit fullscreen mode

Observable base class

public class Observable : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => 
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
Enter fullscreen mode Exit fullscreen mode

BusyViewModel class

A Busy property can be useful to indicate loading behavior in the View for progress indicator, etc.

public class BusyViewModel : ViewModel
    {
        private bool isBusy;

        public bool IsBusy
        {
            get => isBusy;
            set
            {
                if (value == isBusy) return;
                isBusy = value;
                OnPropertyChanged();
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

Collapse
llssprattt profile image
llssprattt

This is not for new programmers at all. You dont show any namespaces to fix all the errors that come across. I get a error when i put in "public T Resolve ()"
this stinks cause i really am looking forward to doing this in shell but cant figure this out at all

Collapse
petermilovcik profile image
PeterMilovcik Author

Thanks for the feedback. I'll remove the post, since it's outdated already.