Get ready ... Independent of the NSOutlineView level in MonoMac!
After hundreds of Google searches, and looking through ObjC, as well as C # code, I finally figured out how to do it! I will post my solution here if someone needs it.
This may or may not be the best way to do this, but it works for me.
Step 1 In the Builder interface, add NSOutlineView. Add 2 columns to it and set their identifier colName and colAge .
Also, while you're on it, add a button to your form.
Step 2 : create an output for NSOutlineView - I named my lvMain because I came from the VCL background. Also create an action for your button (this will be the onClick handler).
Step 3: Save your XIB file and return to Mono - it will update your project file. Now we want to create the model that we want to use for our presentation.
In this example, I will use a simple Person object:
public class Person:NSObject { public string Name { get; set; } public int Age { get; set; } public List<Person> Children { get; set; } public Person (string name, int age) { Name = name; Age = age; Children = new List<Person>(); } }
There was nothing complicated there.
Step 4: Create a data source. In this example, this is what I did:
public class MyDataSource:NSOutlineViewDataSource { /// The list of persons (top level) public List<Person> Persons { get; set; } // Constructor public MyDataSource() { // Create the Persons list Persons = new List<Person>(); } public override int GetChildrenCount (NSOutlineView outlineView, NSObject item) { // If the item is not null, return the child count of our item if(item != null) return (item as Person).Children.Count; // Its null, that means its asking for our root element count. return Persons.Count(); } public override NSObject GetObjectValue (NSOutlineView outlineView, NSTableColumn forTableColumn, NSObject byItem) { // Is it null? (It really shouldnt be...) if (byItem != null) { // Jackpot, typecast to our Person object var p = ((Person)byItem); // Get the table column identifier var ident = forTableColumn.Identifier.ToString(); // We return the appropriate information for each column if (ident == "colName") { return (NSString)p.Name; } if (ident == "colAge") { return (NSString)p.Age.ToString(); } } // Oh well.. errors dont have to be THAT depressing.. return (NSString)"Not enough jQuery"; } public override NSObject GetChild (NSOutlineView outlineView, int childIndex, NSObject ofItem) { // If the item is null, it asking for a root element. I had serious trouble figuring this out... if(ofItem == null) return Persons[childIndex]; // Return the child its asking for. return (NSObject)((ofItem as Person).Children[childIndex]); } public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) { // Straight forward - it wants to know if its expandable. if(item == null) return false; return (item as Person).Children.Count > 0; } }
Step 5 is the best step: Link the data source and add dummy data! We also want to update our view every time we add a new item. This can probably be optimized, but I'm still in the โOh, my God, workingโ zone, so I donโt care now.
// Our Click Action partial void btnClick (NSObject sender) { var p = new Person("John Doe",18); p.Children.Add(new Person("Jane Doe",10)); var ds = lvMain.DataSource as MyDataSource; ds.Persons.Add(p); lvMain.ReloadData(); } public override void AwakeFromNib () { base.AwakeFromNib (); lvMain.DataSource = new MyDataSource(); }
I hope this information can help the troubled souls of MonoMac novices like me.