iPhone TableView Control and Monotouch
Thursday, March 11, 2010 at 3:30AM In this article I explore the Monotouch development experience and port the application written in this blog post. I will show in detail the development of such application and compare the development experience from a .Net c# developer point of view (see About Me). Lets first create a project by clicking new project and selecting iPhone Navigation-based Project. In this program I will load an xml file that contains book information and the book’s title, author image and description will be displayed in a TableView. The user will be able to select a book and navigate to a detail view that will display he books information. I know it is trivial but have to start somewhere.
This is xml file will be loaded during application startup and presented in a TableView.
1: <book>
2: <title>Agile Coaching</title>
3: <author>Rachel Davies and Liz Sedley</author>
4: <image>sdcoach.png</image>
5: <price>34.95</price>
6: <description>Discover how to coach your team to become more Agile. Agile Coaching de-mystifies agile practices—it’s a practical guide to creating strong agile teams. Packed with useful tips from practicing agile coaches Rachel Davies and Liz Sedley, this book gives you coaching tools that you can apply whether you are a project manager, a technical lead, or working in a software team.</description>
7: </book>
8: <book>
9: <title>Agile Web Development with Rails, Third Edition</title>
10: <author>Sam Ruby, Dave Thomas, David Heinemeier Hansson, et al</author>
11: <image>rails3.png</image>
12: <price>43.95</price>
13: <description>Rails just keeps on changing. Rails 2, released in 2008, brings hundreds of improvements, including new support for RESTful applications, new generator options, and so on. And, as importantly, we’ve all learned a lot more about writing Rails applications in the last few years.</description>
14: </book>
The selected project template will generate a navigation based application that contains a UITableView. If you compile and run the application you will be presented by an empty UITableView. The RootViewController.xib file contains the UITableView user interface that can be opened by double clicking on it. This action will open Interface Builder and display the UI controls, but for this application I will not need to modify it. So you can close Interface Builder. The project template also created two source code files, one is a .designer file and the other is a code behind file. The .designer file is modified by the designer every time a change is made through Interface Builder, you will see an example later. The code behind file is where I add functionality through code. The method of interest is ViewDidLoad, and this method is called when the RootViewController.xib is loaded (similar to .Net Forms Load event handler). It is here where I get the path of the Books.xml file and load it. I parse the file, populate a List with Book objects and assigned it to a member variable called books.
1: public override void ViewDidLoad ()
2: {
3: this.Title = "Books";
4: var bookFile = NSBundle.MainBundle.PathForResource("books", "xml");
5:
6: XDocument xmlDoc = XDocument.Load(bookFile);
7:
8: var bookList = new List<Book>();
9:
10: var theBooks = from theBook in xmlDoc.Descendants("book")
11: select new
12: {
13: title = theBook.Element("title").Value,
14: author = theBook.Element("author").Value,
15: image = theBook.Element("image").Value,
16: price = decimal.Parse(theBook.Element("price").Value),
17: description = theBook.Element("description").Value
18: };
19:
20: foreach (var item in theBooks)
21: {
22: Book book = new Book();
23: book.Title = item.title;
24: book.Author = item.author;
25: book.Image = item.image;
26: book.Desc = item.description;
27: book.Price = item.price;
28: bookList.Add(book);
29: }
30:
31: books = bookList.ToArray();
32:
33: base.ViewDidLoad ();
34: //Show an edit button
35: //NavigationItem.RightBarButtonItem = EditButtonItem;
36:
37: this.TableView.Source = new DataSource (this);
38: }
The DataSource class is also generated by the project template. In the NumberOfSections method I return the value of one. In the RowsInSection method I return the number of books loaded. These methods need to be implemented because when the UITableView loads it needs to know the number of sections and the number of rows it has to navigate through and/or display. Since each row corresponds to a UITableViewCell the UITableView will need the data to display in the cell. The following method
UITableViewCell GetCell (UITableView tableView,MonoTouch.Foundation.NSIndexPath indexPath)
will create a new cell, customize its appearance and render the data using UIControls. The UITableView will create new cell instances as it is needed but for optimization purposes as a cell scrolls out of the display, it will be put into this queue. So every time the UITableView needs a cell to display, it will attempt to reuse cells stored in the queue.
1: class DataSource : UITableViewSource
2: {
3: RootViewController controller;
4:
5: public DataSource (RootViewController controller)
6: {
7: this.controller = controller;
8: }
9:
10: public override int NumberOfSections (UITableView tableView)
11: {
12: return 1;
13: }
14:
15: // Customize the number of rows in the table view
16: public override int RowsInSection (UITableView tableview, int section)
17: {
18: return controller.books.Length;
19: }
20:
21:
22: // Customize the appearance of table view cells.
23: public override UITableViewCell GetCell (UITableView tableView,
24: MonoTouch.Foundation.NSIndexPath indexPath)
25: {
26: string cellIdentifier = "Cell";
27: var cell = tableView.DequeueReusableCell (cellIdentifier);
28: if (cell == null) {
29: cell = new UITableViewCell (UITableViewCellStyle.Subtitle, cellIdentifier);
30: }
31:
32: // Configure the cell.
33: Book book = controller.books[indexPath.Row];
34: cell.TextLabel.Text = book.Author;
35: cell.DetailTextLabel.Text = book.Title;
36: cell.ImageView.Image = UIImage.FromFile(book.Image);
37:
38: return cell;
39: }
40:
41:
42: // Override to support row selection in the table view.
43: public override void RowSelected (UITableView tableView,
44: MonoTouch.Foundation.NSIndexPath indexPath)
45: {
46: DetailsViewController detailsViewController = new DetailsViewController();
47: detailsViewController.Book = controller.books[indexPath.Row];
48: controller.NavigationController.PushViewController(detailsViewController, true);
49: }
50: }
Now I want to display a detail view when the user selects a row. Click add new file and select View Interface Definition with Controller template. This template will create a DetailsViewController.xib, DetailsViewController.xib.designer.cs and DetailsViewController.xib.cs files. In a nutshell a Xib file contains a serialized representation of the UI objects that are rendered on the view. I want to navigate to the Details View when the user selects a row and this is shown above on line 43. In this method I instantiate a new DetailsViewController, assign the contents of the selected row to the Book property and navigate to the view. Notice that I navigate to the view by calling PushViewController on the navigation controller.

Double click DetailsViewController.xib to open the file in Interface Builder. Add the following UIControls to the view as shown below. After the UI is designed, select the Library window, click on the classes tab and on the search box at the bottom of the window type DetailsViewController. Once the DetailsViewController is in focus, select the outlets tab and click the “+” button to add the four outlets as shown below.


Now right click on the File’s Owner icon and connect the outlets to the respective Labels. Save and close Interface Builder.

Now look at the DetailsViewController.xib.designer.cs file, you should see code corresponding to the outlets added. This code was auto generated by the MonoDevelop Ide. Once again I modify the ViewDidLoad method as shown below. On line 3 I set the title of the view to the Book title. Finally set the UILabel and UITextView outlets with the correct data.
1: public override void ViewDidLoad ()
2: {
3: base.ViewDidLoad ();
4: Title = Book.Title;
5: bookTitle.Text = Book.Title;
6: author.Text = Book.Author;
7: desc.Text = Book.Desc;
8: price.Text = Book.Price.ToString();
9: }
Conclusion
I am very pleased with the development experience that Monotouch brings to the table. I like that it generates a lot of code for the developer automatically. The autogeneration of outlets is a big plus. I like that the project template gets a lot more done when comparing it to the Xcode project template. In my opinion Monotouch is a good tool to have in your toolbox specially if you are a .Net developer. The possibilities of code reuse accross multiple platforms is something one cannot ignore. I will continue to compare Monotouch development and Xcode development in future articles.
That's it! Hope this helps. The code can be downloaded here.
MonoTouch,
UITableView,
iPhone SDK in
MonoTouch,
iPhone Dev,
iphone sdk 
Reader Comments (1)
Nice post.
Just one tip though: you write your LINQ query and select an IEnumerable of anonymous types. You then loop over them and populate a Book object, then aded it to the list. The query and the loop are two separate steps: but they don't need to be, you can reduce that part of the code by half by doing the following:
var query =
from theBook in xmlDoc.Descendants("book")
select new Book
{
Title = theBook.Element("title").Value
...
};
List<Book> bookList = query.ToList();