Skip to content

Xamarin Cheatsheet

Xamarin - Cross-Platform Mobile Apps with .NET

Xamarin is an open-source platform for building modern and performant applications for iOS, Android, and Windows with .NET. Xamarin is an abstraction layer that manages communication of shared code with underlying platform code.

Table of Contents

Installation

Prerequisites

# Install Visual Studio (Windows) or Visual Studio for Mac (macOS)
# Make sure to include the "Mobile development with .NET" workload

# For iOS development on Windows, you need a Mac with Xcode and Visual Studio for Mac installed

Verify Installation

# Open Visual Studio Installer
# Check if "Mobile development with .NET" is installed

# Check for Android SDK and NDK
# Visual Studio > Tools > Options > Xamarin > Android Settings

# Check for Xcode and Apple SDKs (macOS)
# Visual Studio for Mac > Preferences > Projects > SDK Locations > Apple

Getting Started

Create a New Project

# In Visual Studio
# File > New > Project
# Select "Mobile App (Xamarin.Forms)"
# Choose a template (Blank, Tabbed, Shell)

# In Visual Studio for Mac
# File > New Solution
# Select "Multiplatform > App > Xamarin.Forms"
# Choose a template (Blank, Tabbed, Shell)

Run the App

# Select a startup project (Android or iOS)
# Choose a device or emulator
# Click the "Run" button or press F5

Project Structure

MyApp/
├── MyApp/                  # .NET Standard library (shared code)
│   ├── App.xaml
│   ├── App.xaml.cs
│   ├── MainPage.xaml
│   ├── MainPage.xaml.cs
│   ├── Models/
│   ├── Views/
│   ├── ViewModels/
│   └── Services/
├── MyApp.Android/          # Android-specific project
│   ├── MainActivity.cs
│   ├── Resources/
│   └── Assets/
├── MyApp.iOS/              # iOS-specific project
│   ├── AppDelegate.cs
│   ├── Main.cs
│   └── Info.plist
└── MyApp.sln               # Solution file

Xamarin.Forms

Pages

// ContentPage
public class MyContentPage : ContentPage
{
    public MyContentPage()
    {
        Content = new StackLayout
        {
            Children = { new Label { Text = "Welcome to Xamarin.Forms!" } }
        };
    }
}

// TabbedPage
public class MyTabbedPage : TabbedPage
{
    public MyTabbedPage()
    {
        Children.Add(new MyContentPage { Title = "Tab 1" });
        Children.Add(new MyContentPage { Title = "Tab 2" });
    }
}

// FlyoutPage (Master-Detail)
public class MyFlyoutPage : FlyoutPage
{
    public MyFlyoutPage()
    {
        Flyout = new ContentPage { Title = "Menu" };
        Detail = new NavigationPage(new MyContentPage());
    }
}

Layouts

// StackLayout
new StackLayout
{
    Orientation = StackOrientation.Vertical,
    Spacing = 10,
    Children = { new Label(), new Button() }
};

// Grid
new Grid
{
    RowDefinitions = { new RowDefinition { Height = GridLength.Auto } },
    ColumnDefinitions = { new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } },
    Children = { { new Label(), 0, 0 } }
};

// FlexLayout
new FlexLayout
{
    Direction = FlexDirection.Row,
    JustifyContent = FlexJustify.SpaceBetween,
    Children = { new Label(), new Button() }
};

// AbsoluteLayout
new AbsoluteLayout
{
    Children = { { new BoxView { Color = Colors.Blue }, new Rectangle(0, 0, 100, 100) } }
};

// RelativeLayout
new RelativeLayout
{
    Children = { { new BoxView(), Constraint.Constant(0) } }
};

Controls

// Label
new Label { Text = "Hello, Xamarin!", FontSize = 24 };

// Button
new Button { Text = "Click Me", Command = new Command(() => DisplayAlert("Title", "Message", "OK")) };

// Entry
new Entry { Placeholder = "Enter text" };

// Editor
new Editor { Placeholder = "Enter multi-line text" };

// SearchBar
new SearchBar { Placeholder = "Search..." };

// Slider
new Slider { Minimum = 0, Maximum = 100 };

// Stepper
new Stepper { Minimum = 0, Maximum = 10 };

// Switch
new Switch { IsToggled = true };

// DatePicker
new DatePicker();

// TimePicker
new TimePicker();

// ListView
new ListView
{
    ItemsSource = new[] { "Item 1", "Item 2" },
    ItemTemplate = new DataTemplate(() =>
    {
        var cell = new TextCell();
        cell.SetBinding(TextCell.TextProperty, ".");
        return cell;
    })
};

// CollectionView
new CollectionView
{
    ItemsSource = new[] { "Item 1", "Item 2" }
};

Xamarin.Native

Xamarin.Android

// MainActivity.cs
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.activity_main);

        var button = FindViewById<Button>(Resource.Id.myButton);
        button.Click += (sender, e) =>
        {
            Toast.MakeText(this, "Button Clicked!", ToastLength.Short).Show();
        };
    }
}

Xamarin.iOS

// ViewController.cs
public partial class ViewController : UIViewController
{
    public ViewController(IntPtr handle) : base(handle) { }

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

        var button = new UIButton(UIButtonType.System);
        button.Frame = new CGRect(20, 200, 280, 44);
        button.SetTitle("Click Me", UIControlState.Normal);
        button.TouchUpInside += (sender, e) =>
        {
            var alert = UIAlertController.Create("Title", "Message", UIAlertControllerStyle.Alert);
            alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
            PresentViewController(alert, true, null);
        };
        View.AddSubview(button);
    }
}

XAML

<!-- MainPage.xaml -->
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainPage">
    <StackLayout>
        <Label Text="Welcome to Xamarin.Forms!"
               VerticalOptions="CenterAndExpand" 
               HorizontalOptions="CenterAndExpand" />
        <Button Text="Click Me" Clicked="OnButtonClicked" />
    </StackLayout>
</ContentPage>
// MainPage.xaml.cs
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void OnButtonClicked(object sender, EventArgs e)
    {
        DisplayAlert("Title", "Message", "OK");
    }
}

Data Binding

<!-- ViewModel -->
public class MyViewModel : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

<!-- XAML -->
<ContentPage.BindingContext>
    <local:MyViewModel />
</ContentPage.BindingContext>

<Entry Text="{Binding Name, Mode=TwoWay}" />
<Label Text="{Binding Name}" />
// Push a new page
await Navigation.PushAsync(new DetailsPage());

// Pop a page
await Navigation.PopAsync();

// Pop to root
await Navigation.PopToRootAsync();

// Pass data
await Navigation.PushAsync(new DetailsPage(item));

// Modal navigation
await Navigation.PushModalAsync(new ModalPage());
await Navigation.PopModalAsync();

DependencyService

// Define an interface in shared code
public interface ITextToSpeech
{
    void Speak(string text);
}

// Implement the interface in platform-specific projects
// Android
[assembly: Dependency(typeof(TextToSpeech_Android))]
namespace MyApp.Droid
{
    public class TextToSpeech_Android : ITextToSpeech { ... }
}

// iOS
[assembly: Dependency(typeof(TextToSpeech_iOS))]
namespace MyApp.iOS
{
    public class TextToSpeech_iOS : ITextToSpeech { ... }
}

// Use the service in shared code
DependencyService.Get<ITextToSpeech>().Speak("Hello, Xamarin!");

Custom Renderers

// Create a custom control in shared code
public class MyEntry : Entry { }

// Create a custom renderer in platform-specific projects
// Android
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace MyApp.Droid
{
    public class MyEntryRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                Control.SetBackgroundColor(Android.Graphics.Color.LightGreen);
            }
        }
    }
}

// iOS
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace MyApp.iOS
{
    public class MyEntryRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                Control.BackgroundColor = UIColor.FromRGB(204, 153, 255);
            }
        }
    }
}

Effects

// Create an effect in shared code
public class FocusEffect : RoutingEffect
{
    public FocusEffect() : base("MyApp.FocusEffect") { }
}

// Implement the effect in platform-specific projects
// Android
[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(FocusEffect_Android), "FocusEffect")]
namespace MyApp.Droid
{
    public class FocusEffect_Android : PlatformEffect { ... }
}

// Use the effect in XAML
<Entry>
    <Entry.Effects>
        <local:FocusEffect />
    </Entry.Effects>
</Entry>

MessagingCenter

// Subscribe to a message
MessagingCenter.Subscribe<MainPage, string>(this, "Hi", (sender, arg) =>
{
    // Do something with the message
});

// Send a message
MessagingCenter.Send(this, "Hi", "John");

// Unsubscribe
MessagingCenter.Unsubscribe<MainPage, string>(this, "Hi");

Data Persistence

Preferences

// Set a value
Preferences.Set("my_key", "my_value");

// Get a value
var value = Preferences.Get("my_key", "default_value");

File System

// Get the local app data folder
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var filename = Path.Combine(path, "myfile.txt");

// Write to a file
File.WriteAllText(filename, "Hello, Xamarin!");

// Read from a file
var content = File.ReadAllText(filename);

SQLite

// Install sqlite-net-pcl NuGet package

// Create a model
public class MyItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Text { get; set; }
}

// Create a database connection
var db = new SQLiteAsyncConnection(dbPath);
await db.CreateTableAsync<MyItem>();

// Save an item
await db.InsertAsync(item);

// Get all items
var items = await db.Table<MyItem>().ToListAsync();

Networking

HttpClient

var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/items");
if (response.IsSuccessStatusCode)
{
    var content = await response.Content.ReadAsStringAsync();
    var items = JsonConvert.DeserializeObject<List<MyItem>>(content);
}

Refit

// Install Refit NuGet package

// Define an interface
public interface IMyApi
{
    [Get("/items")]
    Task<List<MyItem>> GetItems();
}

// Use the interface
var api = RestService.For<IMyApi>("https://api.example.com");
var items = await api.GetItems();

Testing

Unit Testing

// Use a testing framework like NUnit or xUnit
[Test]
public void MyViewModel_MyCommand_ShouldDoSomething()
{
    // Arrange
    var viewModel = new MyViewModel();

    // Act
    viewModel.MyCommand.Execute(null);

    // Assert
    Assert.IsTrue(viewModel.MyProperty);
}

UI Testing

// Use Xamarin.UITest
[Test]
public void AppLaunches()
{
    app.Screenshot("First screen.");
}

[Test]
public void TappingButton_ShouldNavigateToDetails()
{
    app.Tap(c => c.Button("MyButton"));
    app.WaitForElement(c => c.Marked("DetailsPage"));
    app.Screenshot("Details screen.");
}

Deployment

Android

# Build the app in Release mode
# Archive the app
# Distribute the archive (e.g., to Google Play)

iOS

# Build the app in Release mode
# Archive the app
# Distribute the archive (e.g., to the App Store)

Best Practices

  • Use MVVM: Separate your UI from your business logic.
  • Use Data Binding: Simplify your UI code and make it more maintainable.
  • Use DependencyService for platform-specific code: Keep your shared code clean.
  • Optimize performance: Use compiled bindings, lazy loading, and other techniques.
  • Write tests: Ensure your app is working correctly.

Troubleshooting

Common Issues

  • Build errors: Check your SDK paths and NuGet packages.
  • Deployment errors: Check your signing keys and provisioning profiles.
  • Runtime errors: Use the debugger and check the device logs.

Summary

Xamarin is a powerful platform for building cross-platform mobile applications with .NET. Its key features include:

  • Native Performance: Xamarin apps are compiled to native code.
  • Native UI: Xamarin provides access to native UI controls.
  • Shared Code: Share up to 90% of your code across platforms.
  • .NET Ecosystem: Leverage the power of the .NET platform and its ecosystem.
  • Visual Studio: Use the powerful Visual Studio IDE for development.

Xamarin is a great choice for .NET developers who want to build cross-platform mobile applications without learning new languages or frameworks.