In a recent blog post, I showed the C# best practices we use at my current placement. Today, the Xamarin best practices:
Xamarin 🐒 Best Practices
The Do’s 🙌
👍 Catch XAML Errors Early
Add the following attribute to code behind in order to improve performance and catch xaml errors early.
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
👍 By convention the identifier for the ViewModel is vm (not Vm or vM)
👍 The only code in code-behind (e.g., foo.xaml.cs) should be
- initialize in the constructor
- create the view model
- assign the datacontext to the view model
- call the viewmodel’s Initialize method
- Lifecycle methods such as OnAppearing and OnDisappearing
Why: we want to keep the code behind as sparse as possible. Unit testing requires reaching into code and that is infinitely easier with a viewmodel.
👍 Every viewmodel should have an initialize method called from the code behind.
Why: Having an initialize method keeps most of the code for the vm out of the constructor. This is recommended practice by Microsoft, and allows for async methods.
👍 Create viewmodel name by appending “viewmodel” to the xaml name
LigthController.xaml
LightController.xaml.cs
LightControllerViewModel.cs
Why: It is far easier to find the file you want if we follow a convention.
👍 Use commands rather than event handlers
// wrong - handled in code behind
<button Text="Divide by 2" Clicked="onClick" />
//correct - handled in viewmodel
<button Text="Divide by 2" ClickedCommand="{Binding DivideBy2Command"
Why: It is much easier to write unit tests when the event handler is in the viewmodel. Update: Use the Xamarin Community Toolkit to create commands out of events.
👍 ListView ItemSource should bind to Observable Collections instead of Lists
Why: Observable Collections provide notifications when items get added, removed, or when the whole list is refreshed. Lists do not provide these notifications. Warning, there is no automatic push notification if a member of the list is changed.
👍 Set BindingContext in ctor of the View CodeBehind
Why: This will prevent timing issues that may prevent the Content Page Title from displaying
👍 Place async method calls in OnAppearing in the View CodeBehind rather than in the constructor
//wrong public PointsListView() { viewModel = new PointListViewModel(pointService, Device, SelectedModule, ObjectType); Task.Run(async()=> await viewModel.PopulateMenuOptions()); } //correct public PointsListView() { } protected override async void OnAppearing() { viewModel = new PointListViewModel(pointService, Device, SelectedModule, ObjectType); await viewModel.PopulateMenuOptions(); }
Why: The ctor should only be initializing the view and should not make calls to controller.
And Microsoft support said so 😄
The Don’ts 🙅
😦 Do not assign more than one view to a view model. Generally speaking, it should be one view to one view model.
😦 Do not put Xaml in templates in App.xaml. Put the Xaml in the Xaml file.
Why: App.xaml quickly becomes bloated and hard to work with. Having the Xaml in the Xaml file is natural and helps create the troika we want: foo.xaml, foo.xaml.cs and fooViewModel.cs.
😦 Do not pass view modes to methods of other pages
😦 Avoid Xaml file names ending in “view”
LightControllerView.xaml
LightControllerView.xaml.cs
LightControllerViewViewModel.cs
Why: Adding view to a view file is redundant and it makes reading the name of the ViewModel more difficult.
😦 Do not end async method names with ‘Async’
Why: It is easy to forget.