I’m working on my presentation for the Alaska .NET Users Group. My goal is to build an app that consumes a web service, and displays the data. After getting the web service piece going, the next step was to display that data in a NSTableView.
I battled for hours and hours trying to figure out how to create a NSTableViewDataSource, and it turns out I was making things way to complicated. I did some searching on the web, but couldn’t really find anything except a post by John Moshakis on the Mono-osx mailing list which gave me some hope that someone had figured it out.
I emailed John, and he was gracious enough to send me some source code to work from. It turns out, I what I had wasn’t far off the mark, I just needed a few pointers.
The DataSource Code
-
using System;
-
using System.Collections;
-
using MonoMac.Foundation;
-
using MonoMac.AppKit;
-
using MovieTimes.BusinessLogic;
-
using System.Collections.Generic;
-
-
[Register("MyItemDataSource")]
-
public class MyItemDataSource : NSTableViewDataSource
-
{
-
public List<MyItem> MyItems { get; set; }
-
-
static MyItemDataSource () {
-
}
-
-
[Export("numberOfRowsInTableView:")]
-
public int numberOfRowsInTableView (NSTableView aTableView) {
-
if (MyItems == null)
-
return 0;
-
return MyItems.Count;
-
}
-
-
[Export("tableView:objectValueForTableColumn:row:")]
-
public NSObject objectValueForTableColumn (NSTableView aTableView, NSTableColumn aTableColumn, int rowIndex) {
-
return new NSString
(MyItems
[rowIndex
].Name); -
}
-
-
public void Items(List<MyItem> items) {
-
MyItems = items;
-
}
-
}
-
-
public class MyItemDataSourceDelegate : NSTableViewDelegate {
-
public event EventHandler<MyItemChangedEventArgs> MyItemChanged;
-
-
public MyItemDataSourceDelegate ():base() {
-
}
-
-
public override void SelectionDidChange(NSNotification notification) {
-
var table = notification.Object as NSTableView;
-
-
var ds = table.DataSource as MyItemDataSource;
-
-
var rowNum = table.SelectedRow;
-
-
if (rowNum >= 0 && rowNum < ds.MyItems.Count)
-
OnMyItemChanged
(new MyItemChangedEventArgs
(ds
.MyItems[rowNum
])); -
}
-
-
protected void OnMyItemChanged(MyItemChangedEventArgs e) {
-
if (MyItemChanged != null)
-
MyItemChanged(this, e);
-
}
-
}
-
-
public class MyItemChangedEventArgs : EventArgs {
-
public MyItem MyItem { get; set; }
-
-
public MyItemChangedEventArgs(MyItem i) {
-
MyItem = i;
-
}
-
}
The code is kind of long, and I’ve removed all the normal guard code you would use for the sake of brevity. But lets dissect the code. The first part, lines 8 – 31 is the actual data source. It simply listens for a few messages (numberOfRowsInTableView and objectValueForTableColumn) and allows items to be added to the data source (line 28). The next part, lines 33 – 54 fire off an event when the selected item has changed in the NSTableView instance.
The Window Code
-
public override void WindowDidLoad () {
-
base.WindowDidLoad ();
-
-
var myDel
= new MyItemDataSourceDelegate
(); -
myDel.ItemChanged += ItemChanged;
-
-
this.someTable.Delegate = myDel;
-
this.someTable.DataSource = new MyItemDataSource
(); -
}
In the window controller, paste the above code to have code run when you window loads. For WinForms people, public override void WindowDidLoad is the equivilent of protected override void OnLoad().
So what does the window controller code do? First off, we create our delegate (note, delegates in Cocoa are not the same thing as in C#), and wire up to the changed event, then we assign the newly created delegate and a data source to our table.
Any questions, thoughts or feedback? Hit me up in the comments, or follow me on twitter.