{"id":12259,"date":"2014-07-01T17:05:27","date_gmt":"2014-07-01T21:05:27","guid":{"rendered":"http:\/\/blog.xamarin.com\/?p=12259"},"modified":"2014-07-01T17:05:27","modified_gmt":"2014-07-01T21:05:27","slug":"introduction-to-f-with-xamarin-part-ii","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/introduction-to-f-with-xamarin-part-ii\/","title":{"rendered":"Introduction to F# with Xamarin, Part II"},"content":{"rendered":"<p>\t\t\t\t<a href=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/rachel-reese.png\"><img decoding=\"async\" class=\"size-full wp-image-11330 alignright\" src=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/rachel-reese.png\" alt=\"rachel-reese\" width=\"100\" height=\"100\" \/><\/a><em>Rachel Reese is a long-time software engineer and math geek who recently relocated to Nashville, TN to work at Firefly Logic. Rachel is an ASPInsider and an F# MVP. You can catch her at Xamarin Evolve 2014, the <a href=\"https:\/\/evolve.xamarin.com\/\">largest conference for cross-platform mobile development<\/a>.<\/em><\/p>\n<p><em>This blog post is part of our continuing celebration of F# Week at Xamarin! Celebrate by getting your own <a href=\"\/run-a-f-sharp-app-get-a-f-sharp-shirt\/\">F# t-shirt<\/a>! Yesterday, Rachel gave us an <a href=\"\/introduction-to-f-with-xamarin\/\">&#8220;Introduction to F# with Xamarin&#8221;<\/a>. Today, she takes us through building a task management app with F# and Xamarin.<\/em><\/p>\n<p><strong>Getting Started with iOS Development<\/strong>\n<img decoding=\"async\" class=\"alignleft\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/04\/iOS-TaskyList.png\" alt=\"\" width=\"184\" height=\"357\" \/> Yesterday, we took a look at the benefits of <a href=\"http:\/\/developer.xamarin.com\/guides\/cross-platform\/fsharp\/fsharp_support_overview\/\" target=\"_blank\">F#<\/a> by building much of the data layer for the F# version of the <a href=\"https:\/\/github.com\/rachelreese\/Tasky\">task-management app Tasky<\/a>. Today, let\u2019s complete that, add a couple of views, and we\u2019ll be up and running with an F# version of Xamarin\u2019s favorite task app!<\/p>\n<p>In Xamarin Studio, create a new F# iOS Single View Application named &#8220;Tasky&#8221;. Xamarin Studio will create a solution for us, with two important files:<\/p>\n<p><strong>1. AppDelegate.fs<\/strong><\/p>\n<ol>\u2013 This is the heart of the application. The Main module defines an application\u2019s entry point, while the AppDelegate type inherits from UIApplicationDelegate, which provides such application lifecycle events as ApplicationDidFinishLaunching and ApplicationWillTerminate. From AppDelegate, we\u2019ll define which view controller should load first. In this case, because the application is named Tasky, the first view controller that\u2019s called is TaskyViewController.fs.<\/ol>\n<p><strong>2. TaskyViewController.fs<\/strong><\/p>\n<ol>\u2013 This is the project\u2019s first view controller. This is inherited from UIViewController, and the main overridable methods here handle the view lifecycle. For example: ViewDidLoad, DidReceiveMemoryWarning, DidRotate, ViewWillDisappear, etc.<\/ol>\n<p>If we run the project at this point, before making any changes, it will load a blank, black screen. Let\u2019s make it do a bit more. We will start by setting up navigation. Open AppDelegate.fs and update the RootViewController to the following:<\/p>\n<p>[code langauge=&#8221;fsharp&#8221;]\nwindow.RootViewController &lt;- new UINavigationController (new TaskyViewController ())\n[\/code]<\/p>\n<p>Wrapping the TaskyViewController in a UINavigationController will allow a user to navigate back from the update task screen (once we create it). In other words, that screen will display a back button allowing return to the task list. That finishes off the changes we\u2019ll need to make for Tasky in AppDelegate.fs.<\/p>\n<p>Next, let\u2019s work on the main view controller. Open TaskyViewController.fs, and we\u2019ll add an event handler in ViewDidLoad, for adding a new task from a \u201c+\u201d button on the navigation bar.<\/p>\n<p>[code langauge=&#8221;fsharp&#8221;]\nlet addNewTask =\n    new EventHandler (fun sender eventargs -&gt;\n        this.NavigationController.PushViewController (new AddTaskViewController (), true)\n    )\nthis.NavigationItem.SetRightBarButtonItem (new UIBarButtonItem (UIBarButtonSystemIcon.Add, addNewTask), false)\n[\/code]<\/p>\n<p>At this point, we\u2019ll also need to create a nearly empty AddTaskViewController.fs, inherited from UIViewController, like so:<\/p>\n<p>[code langauge=&#8221;fsharp&#8221;]\ntype AddTaskViewController () =\n    inherit UIViewController ()\n    override this.ViewDidLoad () =\n        base.ViewDidLoad ()\n[\/code]<\/p>\n<p>Our final project structure will look like this:<\/p>\n<p><a href=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/2014-07-01_1723.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-12264\" src=\"\/wp-content\/uploads\/sites\/44\/2019\/04\/2014-07-01_1723.png\" alt=\"2014-07-01_1723\" width=\"242\" height=\"255\" \/><\/a><strong>Creating and Populating with Data<\/strong><\/p>\n<p>Now that the navigation is set up, let\u2019s build the task list itself. First, create the UITableView:<\/p>\n<pre class=\"lang:fsharp\">\nlet table &lt;- new UITableView ()\n<\/pre>\n<p>Next, within the ViewDidLoad method, set the view\u2019s frame to be the full screen, and add the table to the view.<\/p>\n<pre class=\"lang:fsharp\">\ntable.Frame &lt;- this.View.Bounds\nthis.View.Add table\n<\/pre>\n<p>Displaying the table was the easy part. Next, we\u2019ll need to fill the table with data. To help do this, we need to <a href=\"http:\/\/developer.xamarin.com\/guides\/ios\/user_interface\/tables\/part_2_-_populating_a_table_with_data\/\">create a UITableViewSource<\/a>. In our case, we take in the list of tasks that are returned from the SQLite Type Provider, as well as our navigation controller. We will need to include the navigation controller as a parameter, so that we can navigate when the user clicks a row in the table. We also copy the task list locally, and set the cell identifier to a unique name for this cell type. It\u2019s possible to load a mix of different cell types (with completely varied layouts) into an iOS table, and this identifies which one is being loaded.<\/p>\n<pre class=\"lang:fsharp\">\ntype TaskDataSource(tasksource: task list, navigation: UINavigationController) =\n    inherit UITableViewSource ()\n    let tasks = new List&lt;task&gt; (taskSource)\n    member x.cellIDentifier = &quot;TaskCell&quot;\n<\/pre>\n<p>Once we\u2019ve defined those, there are two methods we absolutely must override in TaskDataSource: RowsInSection, and GetCell. RowsInSection returns the total number of rows that the table contains; GetCell dequeues or creates a new UITableViewCell, then populates that cell with the correct data for that row. [For more information on dequeuing, see the \u201cNote on Cell Reuse\u201d in the Xamarin docs, above.]<\/p>\n<pre class=\"lang:fsharp\">\noverride x.RowsInSection (view, section) = tasks.Count\n\noverride x.GetCell (view, indexPath) =\n    let t = tasks.[indexPath.Item]\n    let cell =\n        let newCell = view.DequeueReusableCell x.cellIdentifier\n        match newCell with\n            | null -&gt; new UITableViewCell (UITableViewCellStyle.Default, x.cellIdentifier)\n            | _ -&gt; newCell\n    cell.TextLabel.Text &lt;- t.Description\n    cell\n<\/pre>\n<p>With these added, let\u2019s jump back to the TaskyViewController type. We need to override ViewWillAppear, to set the newly created TaskDataSource to be the UITableView source. We also must reload the data each time the view appears. Using the GetIncompleteTasks method we created in the type providers section, we should now be able to run Tasky and load the tasks.<\/p>\n<pre class=\"lang:fsharp\">\noverride this.ViewWillAppear animated =\n    base.ViewWillAppear animated\n\n    table.Source &lt;- new TaskDataSource (Data.GetIncompleteTasks (), this.NavigationController)\n    table.ReloadData ()\n<\/pre>\n<p>This will give us the basic set up to load a table of tasks, but we aren\u2019t yet able to navigate to a detail page upon selecting a row, nor are we able to delete with a swipe in from the right.<\/p>\n<p><strong>Swipe to Delete<\/strong>\nAdding the ability to swipe delete is only a matter of adding two more overrides into the TaskDataSource type.<\/p>\n<ul>\n<li>CanEditRow is, logically, whether or not that row can be edited.<\/li>\n<li>CommitEditingStyle handles the deletion. First, delete the task from the data source; second, remove the task from the tasks list; finally, delete that row from the view.<\/li>\n<\/ul>\n<pre class=\"lang:fsharp\">\noverride x.CanEditRow (view, indexPath) = true\noverride x.CommitEditingStyle (view, editingStyle, indexPath) =\n    match editingStyle with\n        | UITableViewCellEditingStyle.Delete -&gt;\n          Data.DeleteTask tasks.[indexPath.Item].Description\n          tasks.RemoveAt (indexPath.Item)\n          view.DeleteRows ( [|indexPath|], UITableViewRowAnimation.Fade)\n        | _ -&gt; Console.WriteLine &quot;CommitEditingStyle:None called&quot;\n<\/pre>\n<p><strong>Selection and Navigating<\/strong>\nThe final step in the TaskyViewController functionality is to handle navigation. To select a row and navigate to a detail page for that row, we only need to override the RowSelected method. In this case, we first want to deselect the row (so that when we return to the view, the row doesn\u2019t remain selected), and then push the new view controller. We\u2019re using the AddTaskViewController, which handles both adding and updating tasks.<\/p>\n<pre class=\"lang:fsharp\">\noverride x&gt;RowSelected (tableView, indexPath) =\n    tableView.DeselectRow (indexPath, false)\n    navigation.PushViewController (new AddTaskViewController (tasks.[indexPath.Item], false), true)\n<\/pre>\n<p>The above code modifies the constructor of the AddTaskViewController (created previously) to accept a current task, as well as a Boolean determining whether or not that task is a new task. We\u2019ll update this in the next section.<\/p>\n<p><strong>Creating a Non-Table View<\/strong>\nWe\u2019re almost done now; we just need to add a quick form to handle adding and updating a task. Let\u2019s start by updating the constructor to accept a task and a Boolean, as just mentioned. To do this, we need to modify the AddTaskViewController type to take in the new parameters. We\u2019ll also add a second, parameterless constructor, which creates an instance of the controller with some defaults \u2013 specifically: Description should be empty, Complete should be false, and the isNew Boolean should be true, exactly as one would expect with a brand new task.<\/p>\n<pre class=\"lang:fsharp\">\ntype AddTaskViewController (task:task, isNew:bool) =\n    inherit UIViewController ()\n    new () = new AddTaskViewController ({Description=&quot;&quot;; Complete=false}, true)\n    override this.ViewDidLoad () =\n        base.ViewDidLoad ()\n<\/pre>\n<p>Now, let\u2019s move into the ViewDidLoad method. Create a new subview to which we will add our fields, and set the background color to white.<\/p>\n<pre class=\"lang:fsharp\">\nlet addView = new UIView (this.View.Bounds)\naddView.BackgroundColor &lt;- UIColor.White\n<\/pre>\n<p>From here, we simply add and position our form elements. We\u2019ll start with a UITextField for the Description, and a UISwitch with corresponding UILabel for our Complete field. We also add an event handler to handle setting Complete on our task when the switch is toggled.<\/p>\n<pre class=\"lang:fsharp\">\nlet description = new UITextField (new RectangleF (20.f, 64.f, 280.f, 50.f))\ndescription.Text &lt;- task.Description\ndescription.Placeholder &lt;- &quot;task description&quot;\naddView.Add description\n\nlet completeLabel = new UILabel (new RectangleF (20.f, 114.f, 100.f, 30.f))\ncompleteLabel.Text &lt;- Complete\naddView.Add completeLabel\n\nlet completeCheck = new UISwitch (new RectnagleF (120.f, 114.f, 200.f, 30.f))\ncompleteCheck.SetState (task.Complete, false)\nlet changeCompleteStatus =\n    new EventHandler (fun sender eventargs -&gt;\n        task.Complete &lt;- completeCheck.On\n    )\n\ncompleteCheck.TouchDragInside.AddHandler changeCompleteStatus\naddView.Add completeCheck\n<\/pre>\n<p>Now that the input part is complete, we need to be able to save new tasks, along with a corresponding label to indicate the operation has completed. Depending on whether or not the task is new, we call the appropriate Add or Update function in our Data file, and then print \u201cAdded\u201d or \u201cUpdated\u201d.<\/p>\n<pre class=\"lang:fsharp\">\nlet addedLabel = new UILabel (new RectangleF (20.f, 214.f, 280.f, 50.f))\naddView.Add addedLabel\n\nlet addUpdateButton = UIButton.FromType (UIButtonType.RoundedRect)\naddUpdateButton.Frame &lt;- new RectangleF (20.f, 164.f, 280.f, 50.f)\n\nlet addUpdateHandler =\n    new EventHandler (fun sender eventargs -&gt;\n        match isNew with\n            | true -&gt;\n                Data.AddTask description.Text\n                addedLabel.Text &lt;- &quot;Added!&quot;\n            | false -&gt;\n                Data.UpdateTask description.Text completeCheck.On\n                addedLabel.Text &lt;- &quot;Updated!&quot;\n        description.Text &lt;- &quot;&quot;\n    )\n\naddUpdateButton.TouchUpInside.AddHandler addUpdateHandler\naddUpdateButton.SetTItle (&quot;Save&quot;, UIControlState.Normal)\naddView.Add addUpdateButton\n<\/pre>\n<p>Since the label was added to indicate that saving is complete, we need to clear the text when we want to add a new task, to minimize confusion, and make it obvious that the new task has also been added. To that end, we add a clear label function that is called when the user clicks back into the Description field.<\/p>\n<pre class=\"lang:fsharp\">\nlet clearLabel =\n    new EventHandler (fun sender eventargs -&gt;\n        addedLabel.Text &lt;- &quot;&quot;\n    )\ndescription.TouchDown.AddHandler clearLabel\n<\/pre>\n<p>Finally, we simply need to add the subview that we\u2019ve been populating to the main view, and we\u2019re done!<\/p>\n<p>[code langauge=&#8221;fsharp&#8221;]\nthis.View.Add addView\n[\/code]<\/p>\n<p>We have just built an F# version of Tasky, Xamarin&#8217;s favorite task-management app! You can get the bits on <a href=\"https:\/\/github.com\/rachelreese\/Tasky\">GitHub<\/a> and follow me on Twitter <a href=\"https:\/\/twitter.com\/rachelreese\">@RachelReese<\/a>.<\/p>\n<p>&nbsp;\t\t<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rachel Reese is a long-time software engineer and math geek who recently relocated to Nashville, TN to work at Firefly Logic. Rachel is an ASPInsider and an F# MVP. You can catch her at Xamarin Evolve 2014, the largest conference for cross-platform mobile development. This blog post is part of our continuing celebration of F# [&hellip;]<\/p>\n","protected":false},"author":1936,"featured_media":39167,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[4],"class_list":["post-12259","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-xamarin-platform"],"acf":[],"blog_post_summary":"<p>Rachel Reese is a long-time software engineer and math geek who recently relocated to Nashville, TN to work at Firefly Logic. Rachel is an ASPInsider and an F# MVP. You can catch her at Xamarin Evolve 2014, the largest conference for cross-platform mobile development. This blog post is part of our continuing celebration of F# [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/12259","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/1936"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=12259"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/12259\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/39167"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=12259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=12259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=12259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}