DEV Community

PeterMilovcik
PeterMilovcik

Posted on Edited 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

Top comments (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 •

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