In this post, I’m going to build a fully functional cross-platform mobile application that consumes an authenticated Web APIs (OAuth authentication).
It’s a personalised To-Do application that you need to enter your phone number then enter the verification code after receiving it via SMS to enter your To-Do list.

All code can be found in my Github repository.

Step 1: Create a new Project

Using your favourite IDE (I’m using Visual Studio for Mac), Create a new solution and in the Multiplatform section choose Blank Forms App and go through the wizard to choose your preferred project directory and targeted platforms. If you need to get familiar on what to fill out in the wizard you can check my previous post
Note: It’s preferred to name the project ToDo just so we can have the same namespace in case you would like to copy paste.😋

Step 2: Consume Authentication API endpoints

  1. I’m going to start with organising the project with folders, so I’ll start with a folder named Interfaces and add a new interface called IAuthenticationService

    using System;
    using System.Net;
    using System.Threading.Tasks;

    namespace ToDo.Interfaces
    {
        public interface IAuthenticationService
        {
            Task Register(string phoneNumber);

            Task<HttpStatusCode> AuthorizeUser(string phoneNumber, string verificationCode);
        }
    }

    As shown from the code above, am listing all the required methods that we’re going to implement later on. They’re two methods Register phone number and Authorize User.
    The first one is to tackle our Web API Registration endpoint to send SMS for the registered phone number with the verification code.
    As for the second one, it will take the phone number and the received verification code to send back the Access token to the consumer so it can be saved in a secure place and later on to be passed with any requests.

  2. Now to start working on the implementation, we will create a new folder named Services and then a new class called AuthenticationService.

    using System;
    using System.Diagnostics;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    using System.Collections.Generic;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System.Net;
    using ToDo.Interfaces;

    namespace ToDo
    {
        public class AuthenticationService : IAuthenticationService
        {
            HttpClient client;
            readonly Uri baseUri = new Uri(Constants.BaseURL);

            public AuthenticationService()
            {
                client = new HttpClient();
                client.MaxResponseContentBufferSize = 256000;
            }

            public async Task Register(string phoneNumber)
            {
                string purgedPhoneNumber = phoneNumber;

                var uri = new Uri(baseUri, api/account/register);

                try
                {
                    if (phoneNumber.Contains(+)) { purgedPhoneNumber = phoneNumber.Replace(+); }
                    var json = string.Concat({\”username\”, purgedPhoneNumber, });
                    var content = new StringContent(json, Encoding.UTF8, application/json);

                    var response = await client.PostAsync(uri, content);
                    if (response.IsSuccessStatusCode)
                    {
                        Debug.WriteLine(@”successfully sent.);
                    }

                }
                catch (Exception ex)
                {
                    Debug.WriteLine(@”ERROR {0}, ex.Message);
                }
            }

            public async Task<HttpStatusCode> AuthorizeUser(string phoneNumber, string verificationCode)
            {
                string purgedPhoneNumber = phoneNumber;
                var uri = new Uri(baseUri, token);

                if (phoneNumber.Contains(+)) { purgedPhoneNumber = phoneNumber.Replace(+); }
                var postBody = new Dictionary<stringstring>()
                    {
                        {username, purgedPhoneNumber},
                        {password, verificationCode},
                        {grant_typepassword}
                    };

                var content = new FormUrlEncodedContent(postBody);

                var response = await client.PostAsync(uri, content);
                if (response.IsSuccessStatusCode)
                {
                    //var storeService = DependencyService.Get<IUserDetailsStore>();
                    var result = await response.Content.ReadAsStringAsync();
                    var jsonData = (JObject)JsonConvert.DeserializeObject(result);

                    var token = jsonData[access_token].Value<string>();
                    //Token should be saved in key chain instead of singleton class
                    //But for demo purposes, ill put it here
                    AccountDetailsStore.Instance.Token = token;
                    //storeService.SaveCredentials(phoneNumber, token);
                }
                return response.StatusCode;
            }
        }
    }

    As shown from the code above, we started our implementation with a constructor to initialize the Http client also we defined properties (the Http client and base URI that is going to be used throughout the class).

    So to start with the first method Register, firstly we do some purging for the parameterized input to remove the + sign if it exists, and prepare the post body which we send username: (the purged number) and then do the post request by passing the full URI and content.

    As for the second method AuthorizeUser, we do the same purging but we send different post body since we received the verification code and we want to get the access token in return.
    So the post body will be:

            {username, purgedPhoneNumber},
            {password, verificationCode},
            {grant_typepassword}

    Afterwards, when we check if the response is 200 (Ok), we need to save the access token in a safe, encrypted place. Now in our case, I made a singleton class to save the access token just for demo purposes but the ideal case should be done using this approach (This going to be covered in step 4 below).

    Note: These methods are marked as async methods and you need to add Newtonsoft package in order to use any JSON related code on the above sample.

  3. As noticed from the above code, am using a static class called Constants to read any static string from it. For now, I just have BaseURL constant in it.

    using System;
    namespace ToDo
    {
        public static class Constants
        {
            public static string BaseURL = https://bookmarkerapp.azurewebsites.net/;
        }
    }

  4. As for the Singleton class we’ve talked about saving the access token in memory, we will create a new folder called Helpers and a new class called AccountDetailsStore.

    using System;
    namespace ToDo
    {
        public sealed class AccountDetailsStore
        {
            private static readonly AccountDetailsStore instance = new AccountDetailsStore();

            private AccountDetailsStore() { }

            public static AccountDetailsStore Instance
            {
                get
                {
                    return instance;
                }
            }

            public string PhoneNumber { getset; }
            public string Token { getset; }
        }
    }

  5. The last step in this phase is to create the Authentication manager, so we’re going to create a new folder called Repositories and then a new class called AuthenticationRepository to call the methods in the interface (we can call any other implementation since we’re doing Dependency Injection).

    using System;
    using System.Threading.Tasks;
    using ToDo.Interfaces;

    namespace ToDo
    {
        public class AuthenticationRepository
        {
            IAuthenticationService authenticationService;

            public AuthenticationRepository(IAuthenticationService service)
            {
                authenticationService = service;
            }

            public Task RegisterAccount(string phoneNumber)
            {
                return authenticationService.Register(phoneNumber);
            }

            public Task<System.Net.HttpStatusCode> AutherizeAccount(string phoneNumber, string verificationCode)
            {
                return authenticationService.AuthorizeUser(phoneNumber, verificationCode);
            }
        }
    }

Step 3: Create Sign-in & Verification pages

In this step, we’re going to build two pages with code sharing of 100%, Sign-in page and verification page using XAML and C#.
To get started we create a new folder called Pages

  1. Sign-in page:
    Add a new ContentPage XAML by right click on the pages folder Add – New File… and the XAML form should look like below:

    <?xml version=1.0 encoding=UTF-8?>
    <ContentPage xmlns=http://xamarin.com/schemas/2014/forms xmlns:x=http://schemas.microsoft.com/winfx/2009/xaml x:Class=ToDo.SignIn>
        <ContentPage.Content>
            <StackLayout Orientation=Vertical VerticalOptions=CenterAndExpand Padding=20,0,20,0>
                <Label HorizontalOptions=Center HorizontalTextAlignment=Center Text=Select your country and enter your phone number in order to sign in>
                </Label>
                <Picker VerticalOptions=CenterAndExpand SelectedIndexChanged=CountryPicker_SelectedIndexChanged x:Name=countryPicker ItemDisplayBinding={Binding name} Title=Select a country…>
                </Picker>
                <Entry x:Name=phoneNumberEntry Keyboard=Telephone Placeholder=Enter your phone>
                </Entry>
                <Button Text=Sign in x:Name=signInButton>
                </Button>
                <ActivityIndicator x:Name=pageActivityIndicator>
                </ActivityIndicator>
                <Label HorizontalOptions=Center HorizontalTextAlignment=Start Text=You will receive an SMS with verification code.>
                </Label>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>

    In this XAML, we’re adding a Stack Layout inside Content Page, if you’re familiar with Content page you probably know it only takes single view so we usually insert a container such as Stack layout or scroll view.
    In this Stack layout, I’m adding controls in a vertical order and each control is centralised in the middle. As you can also see that I’ve added some properties for the stack layout like the padding to add some spaces around it.
    Now in stack layout from top to bottom, there is an informative label for the users, a picker to select a country of their phone number (Which I talk more about soon), an entry control where the user can write their phone number, the sign in button, an activity indicator to show that there is a process happening at the moment and finally anther informative label.

    No for the C# code behind:

    using System;
    using System.Collections.Generic;
    using Xamarin.Forms;
    using Newtonsoft.Json;
    using System.IO;
    using System.Reflection;
    using System.Linq;

    namespace ToDo
    {
        public partial class SignIn : ContentPage
        {
            AuthenticationRepository autheticationRepo = new AuthenticationRepository(new AuthenticationService());

            bool isLoading
            {
                set
                {
                    pageActivityIndicator.IsVisible = value;
                    pageActivityIndicator.IsRunning = value;
                    signInButton.IsVisible = !value;
                    this.IsBusy = value;
                }
            }

            public SignIn()
            {
                InitializeComponent();
                Title = Sign in;

                configureCountryPicker();
                configureSignInButton();
                pageActivityIndicator.BindingContext = this;
            }

            private void configureCountryPicker()
            {
                countryPicker.ItemsSource = getCountries();
                countryPicker.SelectedIndexChanged += CountryPicker_SelectedIndexChanged;
            }

            private void configureSignInButton()
            {
                signInButton.Clicked += SignInButton_Clicked;
            }

            private List<Models.CountryCode> getCountries()
            {
                var assembly = typeof(SignIn).GetTypeInfo().Assembly;
                Stream stream = assembly.GetManifestResourceStream(ToDo.Data.Countries.json);

                List<Models.CountryCode> countryCodes;

                using (var reader = new System.IO.StreamReader(stream))
                {
                    var json = reader.ReadToEnd();
                    countryCodes = JsonConvert.DeserializeObject<List<Models.CountryCode>>(json);
                }
                return countryCodes;
            }

            private bool validateForm()
            {
                if (countryPicker.SelectedIndex == –1return false;
                if (string.IsNullOrWhiteSpace(phoneNumberEntry.Text)) return false;
                return true;
            }

            void CountryPicker_SelectedIndexChanged(object sender, EventArgs e)
            {
                if (countryPicker.SelectedIndex == –1) { return; }
                var selectCountry = (Models.CountryCode)countryPicker.SelectedItem;
                phoneNumberEntry.Text = selectCountry.dial_code;
            }

            async void SignInButton_Clicked(object sender, EventArgs e)
            {
                if (!validateForm()) { await DisplayAlert(ValidationPlease fill missing field(s)Ok); return; };
                isLoading = true;
                var phoneNumber = phoneNumberEntry.Text.Trim();
                await autheticationRepo.RegisterAccount(phoneNumber);
                await Navigation.PushAsync(new VerificationPage(phoneNumber));
                isLoading = false;
            }
        }
    }

    This is a partial class SignIn and a child class of ContentPage.
    In the constructor, We’re doing the setup for the page: the title, configuring the country picker, configuring the sign in button and assigning the page activity indicator contexts to self.
    In the configureCountryPicker(), We’re assigning the items data source for this picker by reading a country list JSON file, also in this function, we’re assigning the event method handler when selected index changed.
    As for the configureSignInButton(), we’re also assigning the event method handler when the button is clicked.
    In getCountries() method, we’re reading the JSON file which can be found in here. To add this JSON file, create a new project folder named Data and right click then add files… and choose the JSON downloaded from the above link. Make sure to mark it as embedded resource afterwards.
    It’s important to mention the server call that we do when users click (tap) on the sign in button, we just call the method from the repository AutherizeAccount found in autheticationRepo initialized in the property at the top.
    Then add a new folder and name it Models, to add a POCO class named CountryCode, just to bind it with the results of reading the JSON file.

    using System;
    namespace ToDo.Models
    {
        public class CountryCode
        {
            public string name { getset; }
            public string dial_code { getset; }
            public string code { getset; }
        }
    }

  2. Verification Page:
    This page is where users enter the verification code received via SMS to be redirected to the To-Do list.
    Add a new ContentPage XAML by right click on the pages folder Add – New File… the XAML form should look like below:

    <?xml version=1.0 encoding=UTF-8?>
    <ContentPage xmlns=http://xamarin.com/schemas/2014/forms xmlns:x=http://schemas.microsoft.com/winfx/2009/xaml x:Class=ToDo.VerificationPage>
        <ContentPage.Content>
            <StackLayout Orientation=Vertical VerticalOptions=CenterAndExpand Padding=20,0,20,0>
                <Label Text=Enter verification code>
                </Label>
                <Entry Keyboard=Numeric x:Name=verificationEntry Placeholder=e.g. 1234>
                </Entry>
                <Button x:Name=signInButton Text=Sign in>
                </Button>
                <ActivityIndicator x:Name=pageActivityIndicator>
                </ActivityIndicator>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>

    This page is simpler than the one we added previously, just a stack layout inside a content page with simple controls to let users add their verification code.
    Note the x:Name is like “id” property in ASP.Net web forms world, we can access this control from the server side because of this property.
    And below is the C# code for this page:

    using System;
    using System.Net;

    using Xamarin.Forms;

    namespace ToDo
    {
        public partial class VerificationPage : ContentPage
        {
            AuthenticationRepository autheticationRepo = new AuthenticationRepository(new AuthenticationService());
            string phoneNumber;

            bool isLoading
            {
                set
                {
                    pageActivityIndicator.IsVisible = value;
                    pageActivityIndicator.IsRunning = value;
                    signInButton.IsVisible = !value;
                    this.IsBusy = value;
                }
            }

            public VerificationPage(string phoneNumber)
            {
                InitializeComponent();

                this.phoneNumber = phoneNumber;
                Title = Verify yourself;
                configureSignInButton();
            }

            private void configureSignInButton()
            {
                signInButton.Clicked += SignInButton_Clicked;
            }

            async void SignInButton_Clicked(object sender, EventArgs e)
            {
                var verificationCode = verificationEntry.Text.Trim();
                isLoading = true;
                var isSuccess = await autheticationRepo.AutherizeAccount(phoneNumber, verificationCode);
                if (isSuccess == HttpStatusCode.OK)
                {
                    await Navigation.PushAsync(new MainPage());
                }
                else
                {
                    await DisplayAlert(Ops…Something went wrong, please try again laterOk);
                }
                isLoading = false;
            }
        }
    }

    The main functionality of this page is to call the AutherizeAccount and retrieve the access token to be coupled with any endpoint request later on (operation endpoints).

  3. This step is just to make sure that you change the main page of the app by changing one line in App.xaml.cs

    MainPage = new NavigationPage(new SignIn());

Step 4: Consume CRUD operations

Now to consume all the Create, Read, Update and Delete operations for the To-Do list, we’re going to do the same thing as previously, Create an interface for all the required methods and implement them in the service class and finally consume them in the Repository class.

  1. Let start with the interface, we shall name the interface with IToDoService (Surly inside Interfaces folder).

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Threading.Tasks;
    using ToDo.Models;

    namespace ToDo.Interfaces
    {
        public interface IToDoService
        {
            Task<List<ToDoItem>> GetToDoList();

            Task<HttpStatusCode> DeleteToDoItem(int itemId);

            Task<Uri> AddNewToDoItem(ToDoItem item);

            Task<ToDoItem> UpdateToDoItem(int id, ToDoItem item);
        }
    }

    As you can see from the code above, these are asynchronous methods some of them take id as integer and some take item DTO.
    So apparently we need to create this DTO which called ToDoItem, shall we?

    using System;
    namespace ToDo.Models
    {
        public class ToDoItem
        {
            public int Id { getset; }
            public string Name { getset; }
            public string Notes { getset; }
            public bool Done { getset; }
        }
    }

  2. Now we start with the implementation, create a new class named ToDoService inside the Services folder:

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using ToDo.Interfaces;
    using ToDo.Models;
    using Xamarin.Forms;

    namespace ToDo
    {
        public class ToDoService : IToDoService
        {
            //I recommend to use 
            //https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

            HttpClient client;
            //IUserDetailsStore storeService;
            readonly string token;
            readonly Uri baseUri = new Uri(Constants.BaseURL);

            public ToDoService()
            {
                //storeService = DependencyService.Get<IUserDetailsStore>();
                token = AccountDetailsStore.Instance.Token;
                client = new HttpClient();
                client.MaxResponseContentBufferSize = 256000;
            }

            public async Task<HttpStatusCode> DeleteToDoItem(int id)
            {
                var uri = new Uri(baseUri, string.Format(api/todo/{0}, id));

                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add(Authorizationstring.Format(Bearer {0}, token));

                var response = await client.DeleteAsync(uri);

                return response.StatusCode;
            }

            public async Task<Uri> AddNewToDoItem(ToDoItem item)
            {
                var uri = new Uri(baseUri, api/todo/);

                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add(Authorizationstring.Format(Bearer {0}, token));

                var json = JsonConvert.SerializeObject(item);
                var content = new StringContent(json, Encoding.UTF8, application/json);
                var response = await client.PostAsync(uri, content);

                response.EnsureSuccessStatusCode();

                // Return   the URI of the created resource.
                return response.Headers.Location;
            }

            public async Task<ToDoItem> UpdateToDoItem(int id, ToDoItem item)
            {
                var uri = new Uri(baseUri, string.Format(api/todo/{0}, id));

                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add(Authorizationstring.Format(Bearer {0}, token));

                var json = JsonConvert.SerializeObject(item);
                var content = new StringContent(json, Encoding.UTF8, application/json);
                var response = await client.PutAsync(uri, content);

                // Deserialize the updated product from the response body.
                var responseContent = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<ToDoItem>(responseContent);
            }

            public async Task<List<ToDoItem>> GetToDoList()
            {
                var uri = new Uri(baseUri, api/todo/);

                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add(Authorizationstring.Format(Bearer {0}, token));

                var response = await client.GetAsync(uri);

                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    return JsonConvert.DeserializeObject<List<ToDoItem>>(content);
                }
                return new List<ToDoItem>();
            }
        }
    }

    So in this implementation, we have few properties the http client, a string token and base URI. In the constructor, we’re initializing them and filling out the access token saved in the singleton class which was filled genuinely in the Authentication service.
    Now in each method, we’re doing separate API calls GET, POST, DELETE and PUT. As you can see we’re passing the Authorization header with Bearer accessToken.
    Also making sure the content of each request is UTF8 encoded.

  3. Let’s do the Repository ToDoRepository:

    using System;
    using System.Net;
    using System.Threading.Tasks;
    using System.Collections.Generic;
    using ToDo.Interfaces;
    using ToDo.Models;

    namespace ToDo
    {
        public class ToDoRepository
        {
            readonly IToDoService todoService;

            public Task<List<ToDoItem>> GetToDoList()
            {
                return todoService.GetToDoList();
            }

            public ToDoRepository(IToDoService todoService)
            {
                this.todoService = todoService;
            }

            public Task<HttpStatusCode> DeleteToDoItem(int itemId)
            {
                return todoService.DeleteToDoItem(itemId);
            }

            public Task<Uri> AddNewToDoItem(ToDoItem item)
            {
                return todoService.AddNewToDoItem(item);
            }

            public Task<ToDoItem> UpdateToDoItem(int id, ToDoItem item)
            {
                return todoService.UpdateToDoItem(id, item);
            }
        }
    }

Step5: ToDo list and Add/Edit pages

By right clicking on the Pages folder then add Forms ContentPage XAML and name it MainPage with the following XAML

<?xml version=1.0 encoding=UTF-8?>
<ContentPage xmlns=http://xamarin.com/schemas/2014/forms xmlns:x=http://schemas.microsoft.com/winfx/2009/xaml x:Class=ToDo.MainPage>
    <ContentPage.Content>
        <ListView x:Name=todoListView ItemSelected=todoListView_ItemSelected>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.ContextActions>
                            <MenuItem Text=Delete IsDestructive=True Clicked=OnTaskDelete CommandParameter={Binding Id} />
                        </ViewCell.ContextActions>
                        <StackLayout Padding=20,0,0,0 HorizontalOptions=StartAndExpand Orientation=Horizontal>
                            <Label Text={Binding Name} VerticalTextAlignment=Center />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.Footer>
                <Button x:Name=AddTaskButton Text=Add task></Button>
            </ListView.Footer>
        </ListView>
    </ContentPage.Content>
</ContentPage>

This page looks like a UITableView in the iOS world and ListView in Android world, we’re defining the cell template here to be a stack layout and have a label in it which will contain the to-do item title. Having stack layout as a template will give us the capability to add more controls later on.

Also, you will notice that we have defined the menu item, which is the delete button.
The delete button will behave according to the platform, press and hold on Android and swipe the cell to the left to see the delete button in iOS and by having command parameter we’re going to pass the ID to the function which is in our case OnTaskDelete.


If you notice, we have “Add task” button at the footer of this list view to redirect users to the Add/Edit page and also by having this button at the footer we’re preventing list view from having extra empty cells. Definitely, it’s going to look lame if we have extra empty cells.
now going to C# code:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ToDo.Models;
using Xamarin.Forms;

namespace ToDo
{
    public partial class MainPage : ContentPage
    {
        ToDoRepository todoRepo = new ToDoRepository(new ToDoService());

        public MainPage()
        {
            InitializeComponent();

            configurePage();
        }

        private void configurePage()
        {
            Title = To do list;
            AddTaskButton.Clicked += AddTaskButton_Clicked;
            NavigationPage.SetHasBackButton(thisfalse);
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            var _ = configureTodoList();
        }

        private async Task configureTodoList()
        {
            todoListView.ItemsSource = await todoRepo.GetToDoList();
        }

        void AddTaskButton_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new ItemDetailsPage(new ToDoItem()));
        }

        void todoListView_ItemSelected(object sender, Xamarin.Forms.SelectedItemChangedEventArgs e)
        {
            var todoItem = e.SelectedItem as ToDoItem;
            var itemDetailsPage = new ItemDetailsPage(todoItem)
            {
                BindingContext = todoItem
            };
            Navigation.PushAsync(itemDetailsPage);
        }

        public async void OnTaskDelete(object sender, EventArgs e)
        {
            var menuItem = ((MenuItem)sender);
            var taskId = (Int32)menuItem.CommandParameter;
            var isConfirmed = await DisplayAlert(Delete ConfirmationAre you sure you want to delete this task?ConfirmCancel);

            if (isConfirmed)
            {
                await todoRepo.DeleteToDoItem(taskId);
                await configureTodoList();
            }
        }
    }
}

Again, As I usually do, I start explaining the constructor. Oh, there is nothing abnormal here just removing the back button to not get back to the verification page nor sign in one. also, we’re assigning the event handler for the add task button.

Finally, Add/Edit page named ItemDetailsPage:

<?xml version=1.0 encoding=UTF-8?>
<ContentPage xmlns=http://xamarin.com/schemas/2014/forms xmlns:x=http://schemas.microsoft.com/winfx/2009/xaml x:Class=ToDo.ItemDetailsPage>
    <ContentPage.Content>
        <StackLayout Orientation=Vertical VerticalOptions=StartAndExpand Padding=20,0,20,0>
            <Label Text=Name>
            </Label>
            <Entry x:Name=nameEntry Keyboard=Default Text={Binding Path=Name} Placeholder=task name>
            </Entry>
            <Label Text=Notes>
            </Label>
            <Editor x:Name=notesEditor HeightRequest=90 Keyboard=Default Text={Binding Path=Notes}>
            </Editor>
            <Label Text=Done>
            </Label>
            <Switch x:Name=doneSwitch IsToggled={Binding Path=Done}>
            </Switch>
            <Button Text=Save x:Name=saveItemButton VerticalOptions=CenterAndExpand Clicked=SaveItemButton_Clicked>
            </Button>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Regular content page with controls in it to represent a form for adding or editing tasks.
C# code:

using System;
using System.Collections.Generic;
using ToDo.Models;
using Xamarin.Forms;

namespace ToDo
{
    public partial class ItemDetailsPage : ContentPage
    {
        ToDoItem toDoItem;
        ToDoRepository toDoRepo = new ToDoRepository(new ToDoService());

        public ItemDetailsPage(ToDoItem item)
        {
            InitializeComponent();
            this.toDoItem = item;
            Title = Details;
        }

        async void SaveItemButton_Clicked(object sender, System.EventArgs e)
        {
            toDoItem.Name = nameEntry.Text.Trim();
            toDoItem.Notes = notesEditor.Text.Trim();
            toDoItem.Done = doneSwitch.IsToggled;

            if (toDoItem.Id == 0)
            {
                await toDoRepo.AddNewToDoItem(toDoItem);
            }
            else
            {
                await toDoRepo.UpdateToDoItem(toDoItem.Id, toDoItem);
            }
            await Navigation.PopAsync(true);
        }
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s