In most cases the default AlertDialog is good enough for your needs. You can even pass in a collection of items and event handlers. However, there are times where you'd like more control over the customisation of the dialog. Here you've got two choices:

  1. Use dialog fragments

  2. Pass in a custom view into the AlertDialog - this is what the blog post is about

Define your Dialog.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:baselineAligned="true">
            <TextView
                android:id="@+id/text1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textStyle="bold" />
            <TextView
                android:id="@+id/text2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

Define your row template axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/title_layout"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/dialogtitle"
            android:paddingLeft="16dp"
            android:paddingTop="16dp"
            android:paddingBottom="2dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Title" />
        <TextView
            android:id="@+id/dialogsubtitle"
            android:paddingLeft="16dp"
            android:paddingTop="2dp"
            android:paddingBottom="8dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Subtitle" />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/select_dialog_listview_layout"
        android:paddingBottom="32dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ListView
            android:id="@+id/select_dialog_listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

Create a method to launch your dialog

public Task<int> ShowCustomDialogAsync(string title, string subtitle, MyTestViewModel[] options) {
    var taskCompletionSource = new TaskCompletionSource<int>();
    var activity = Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;
    var dialogBuilder = new AlertDialog.Builder(activity);
    LayoutInflater inflater = activity.LayoutInflater;
    View view = inflater.Inflate(Resource.Layout.AcceptOrderDialog, null);
    dialogBuilder.SetView(view);
    var dialogTitle = (TextView)view.FindViewById(Resource.Id.dialogtitle);
    dialogTitle.Text = title;
    var dialogSubtitle = (TextView)view.FindViewById(Resource.Id.dialogsubtitle);
    if (!string.IsNullOrEmpty(subtitle)) {
        dialogSubtitle.Text = subtitle;
        dialogSubtitle.Visibility = ViewStates.Visible;
    } else {
        dialogSubtitle.Visibility = ViewStates.Gone;
    }
    var dialog = dialogBuilder.Create();
    var primaryList = (ListView)view.FindViewById(Resource.Id.select_dialog_listview);
    primaryList.Adapter = new AcceptTimeOptionViewModelAdapter(dialogBuilder.Context, Resource.Layout.Dialog, options);
    primaryList.Divider = null;
    primaryList.DividerHeight = 0;
    primaryList.ItemClick += (sender, e) => {
        taskCompletionSource.TrySetResult(e.Position);
        dialog.Dismiss();
        dialog.Dispose();
    };
    dialog.CancelEvent += delegate {
        taskCompletionSource.TrySetResult(-1);
    };
    dialog.SetCanceledOnTouchOutside(true);
    dialog.Show();
    return taskCompletionSource.Task;
}

Create a custom adapter

public class MyTestViewModelAdapter : ArrayAdapter<MyTestViewModel> {
    readonly MyTestViewModel[] _options;
    public MyTestViewModelAdapter(Context context, int textViewResourceId, AcceptTimeOptionViewModel[] options) : base(context, textViewResourceId, options) {
        _options = options;
    }
    public override View GetView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (view == null) {
            var vi = (LayoutInflater)Context.GetSystemService(Context.LayoutInflaterService);
            view = vi.Inflate(Resource.Layout.Include_AcceptTime, null);
        }
        MyTestViewModel option = _options[position];
        if (option != null) {
            var text1 = (TextView)view.FindViewById(Resource.Id.text1);
            if (text1 != null) {
                text1.Text = option.SomeString;
            }
        }
        return view;
    }
}

...and there you have it. Customise your dialog axml and rowlayout axml to your hearts content.