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 forAutofac
(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 newBootstrap
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);
}
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 suffixViewModel
and Views are named with suffixView
(e.g., ItemsView, ItemsViewModel). -
AutoWireViewModelProperty
is used to enable this auto wiring for theView
. - Make sure that your View XAML files and classes are renamed accordingly. (ItemsPage to ItemsView).
- Register
ViewModel
type in theAppContainer
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;
}
}
}
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);
}
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));
}
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();
}
}
}
Top comments (2)
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
Thanks for the feedback. I'll remove the post, since it's outdated already.