I was playing around some more with UITableViews and wanted to get them working the way they do in Contacts with the vertical bar on the right side of the screen providing navigation to a certain section in the list (in the case of Contacts and this example, first letter of the word).
It is amazingly simple. Basically you only have to override and implement a few more functions of UITableDataSource… mainly SectionIndexTitles, NumberOfSections, TitleForHeader (and TitleForFooter if you wanted a footer), SectionFor, and RowsInSection. So maybe that wasn’t just a few but they are really simple to implement.
SectionIndexTitles : This is just a string[] with all the titles you want to show on the right side scrollbar area.
NumberOfSections : Simply just a count of the number of sections.
TitleForHeader : This will set the header title for each section. There is an int parameter and for me just returns the string at the specified index.
RowsInSection : This returns a count of the items in the current section. Using .FindAll() in my code.
SectionFor : Not exactly sure what this is for as of yet. Seeing it used in some Obj-c code it just returned the atIndex param. Will look into this more or would love a commentor to explain it.
To spice this demo up I even hooked up a UISearchBar and filter the list on each keystroke. You can notice both the items and sections being filtered out.
Here is what it looks like when it first loads up

And this it the program after searching for something

Here is the code. All of the delegates are in the Main.cs file.
Here is the MainWindow.designer.cs
namespace SectionedUITableViewSample {
// Base type probably should be MonoTouch.Foundation.NSObject or subclass
[MonoTouch.Foundation.Register("AppDelegate")]
public partial class AppDelegate {
[MonoTouch.Foundation.Connect("window")]
private MonoTouch.UIKit.UIWindow window {
get {
return ((MonoTouch.UIKit.UIWindow)(this.GetNativeField("window")));
}
set {
this.SetNativeField("window", value);
}
}
[MonoTouch.Foundation.Connect("tvc")]
private MonoTouch.UIKit.UITableViewController tvc {
get {
return ((MonoTouch.UIKit.UITableViewController)(this.GetNativeField("tvc")));
}
set {
this.SetNativeField("tvc", value);
}
}
[MonoTouch.Foundation.Connect("tv")]
private MonoTouch.UIKit.UITableView tv {
get {
return ((MonoTouch.UIKit.UITableView)(this.GetNativeField("tv")));
}
set {
this.SetNativeField("tv", value);
}
}
[MonoTouch.Foundation.Connect("searchBar")]
private MonoTouch.UIKit.UISearchBar searchBar {
get {
return ((MonoTouch.UIKit.UISearchBar)(this.GetNativeField("searchBar")));
}
set {
this.SetNativeField("searchBar", value);
}
}
}
}
And here is the Main.cs
namespace SectionedUITableViewSample
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// If you have defined a view, add it here:
// window.AddSubview (navigationController.View);
TableViewDataSource tvdc = new TableViewDataSource();
this.tvc.TableView.DataSource = tvdc;
this.searchBar.Delegate = new SearchDelegate(tvc, tvdc);
window.AddSubview(this.tvc.View);
window.MakeKeyAndVisible ();
return true;
}
// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
public class SearchDelegate : UISearchBarDelegate
{
public UITableViewController tvc;
public TableViewDataSource tvdc;
public SearchDelegate(UITableViewController tvc, TableViewDataSource tvdc) : base ()
{
this.tvc = tvc;
this.tvdc = tvdc;
}
public override void TextChanged (UISearchBar searchBar, string searchText)
{
tvdc.Search(searchText);
tvc.TableView.DataSource = tvdc;
tvc.TableView.ReloadData();
}
}
public class TableViewDataSource : UITableViewDataSource
{
private List sectionList;
private List filteredSectionList = new List();
private List dictionaryItems = new List();
public List filteredDictionaryItems = new List();
public TableViewDataSource ()
{
Initialize();
}
public void Initialize()
{
sectionList = new List {"A","B","C","D","E","F","G","H","J","I","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" };
filteredSectionList = new List {"A","B","C","D","E","F","G","H","J","I","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" };
var random = new System.Random();
for(int i = 0; i < 2000; i++)
{
dictionaryItems.Add(sectionList[random.Next(26)] + sectionList[random.Next(26)] + sectionList[random.Next(26)] + sectionList[random.Next(26)]);
}
dictionaryItems.Sort();
foreach(var item in dictionaryItems)
{
filteredDictionaryItems.Add(item);
}
}
public void Search(string searchText)
{
filteredDictionaryItems.Clear();
filteredSectionList.Clear();
foreach(string item in dictionaryItems)
{
if(item.ToLower().Contains(searchText.ToLower()))
{
filteredDictionaryItems.Add(item);
if(filteredSectionList.Find(x => x == item[0].ToString()) == null)
{
filteredSectionList.Add(item[0].ToString());
}
}
}
filteredSectionList.Sort();
}
public override string[] SectionIndexTitles (UITableView tableView)
{
return filteredSectionList.ToArray();
}
public override int NumberOfSections (UITableView tableView)
{
return filteredSectionList.Count;
}
public override string TitleForHeader (UITableView tableView, int section)
{
return filteredSectionList[section];
}
public override int RowsInSection (MonoTouch.UIKit.UITableView tableview, int section)
{
return filteredDictionaryItems.FindAll(x => x.StartsWith(filteredSectionList[section])).Count;
}
public override UITableViewCell GetCell (MonoTouch.UIKit.UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
var termsinsection = filteredDictionaryItems.FindAll(x => x.StartsWith(filteredSectionList[indexPath.Section]));
string dictionaryItem = termsinsection[indexPath.Row];
string cellID = "CellID";
UITableViewCell cell = tableView.DequeueReusableCell(cellID);
if(cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Default, cellID);
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
}
cell.TextLabel.Text = dictionaryItem;
return cell;
}
public override int SectionFor (UITableView tableView, string title, int atIndex)
{
return atIndex;
}
}
}
The code is up on Github