Implementing NSOutlineViewDataSource using MonoMac
-
27-10-2019 - |
Pergunta
I'm trying to implement a datasource for an NSOutlineView
. The problem is that I don't know what type of object to return from outlineView:child:ofItem:
.
Current code looks like this:
[Export("outlineView:child:ofItem:")]
public NSObject childOfItem(NSOutlineView outline, int child, NSObject item)
{
return new MyItem();
}
With MyItem:
public class MyItem : NSObject
{}
EDIT: With this code, I get an InvalidCastException
just after returning MyItem.
Solução
If you inherit a new type from NSOutlineViewDataSource
then you should not re-export its outlineView:child:ofItem:
selector on your own method. Instead what you should do is override the GetChild
method that already export this selector, e.g.
public overrride NSObject GetChild (NSOutlineView outlineView, int childIndex, NSObject ofItem)
{
return new MyItem ();
}
Note: that might not help since I have not tried it (I mostly do MonoTouch things) but do review other selectors you might be redefining/exporting in your application (to see if you should not be override-ing them from the base class you're inheriting from).
Outras dicas
Have you considered using a NSTreeController
? It helps manage the outline view for you and is very handy. NSTreeController
uses a class called NSTreeNode
to represent nodes in the outline view, and each NSTreeNode
has a representedObject
method that allow you to get to the model object.
In any case, if you don't want to use the NSTreeController
or NSTreeNode
, you can just return your model object directly. Here are some sample Objective-C code from apple guides.
@implementation DataSource
// Data Source methods
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
return (item == nil) ? 1 : [item numberOfChildren];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
return (item == nil) ? YES : ([item numberOfChildren] != -1);
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
return (item == nil) ? [FileSystemItem rootItem] : [(FileSystemItem *)item childAtIndex:index];
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
return (item == nil) ? @"/" : [item relativePath];
}
@end
@interface FileSystemItem : NSObject
{
NSString *relativePath;
FileSystemItem *parent;
NSMutableArray *children;
}
+ (FileSystemItem *)rootItem;
- (NSInteger)numberOfChildren;// Returns -1 for leaf nodes
- (FileSystemItem *)childAtIndex:(NSUInteger)n; // Invalid to call on leaf nodes
- (NSString *)fullPath;
- (NSString *)relativePath;
@end
@implementation FileSystemItem
static FileSystemItem *rootItem = nil;
static NSMutableArray *leafNode = nil;
+ (void)initialize {
if (self == [FileSystemItem class]) {
leafNode = [[NSMutableArray alloc] init];
}
}
- (id)initWithPath:(NSString *)path parent:(FileSystemItem *)parentItem {
self = [super init];
if (self) {
relativePath = [[path lastPathComponent] copy];
parent = parentItem;
}
return self;
}
+ (FileSystemItem *)rootItem {
if (rootItem == nil) {
rootItem = [[FileSystemItem alloc] initWithPath:@"/" parent:nil];
}
return rootItem;
}
// Creates, caches, and returns the array of children
// Loads children incrementally
- (NSArray *)children {
if (children == nil) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *fullPath = [self fullPath];
BOOL isDir, valid;
valid = [fileManager fileExistsAtPath:fullPath isDirectory:&isDir];
if (valid && isDir) {
NSArray *array = [fileManager contentsOfDirectoryAtPath:fullPath error:NULL];
NSUInteger numChildren, i;
numChildren = [array count];
children = [[NSMutableArray alloc] initWithCapacity:numChildren];
for (i = 0; i < numChildren; i++)
{
FileSystemItem *newChild = [[FileSystemItem alloc]
initWithPath:[array objectAtIndex:i] parent:self];
[children addObject:newChild];
[newChild release];
}
}
else {
children = leafNode;
}
}
return children;
}
- (NSString *)relativePath {
return relativePath;
}
- (NSString *)fullPath {
// If no parent, return our own relative path
if (parent == nil) {
return relativePath;
}
// recurse up the hierarchy, prepending each parent’s path
return [[parent fullPath] stringByAppendingPathComponent:relativePath];
}
- (FileSystemItem *)childAtIndex:(NSUInteger)n {
return [[self children] objectAtIndex:n];
}
- (NSInteger)numberOfChildren {
NSArray *tmp = [self children];
return (tmp == leafNode) ? (-1) : [tmp count];
}
- (void)dealloc {
if (children != leafNode) {
[children release];
}
[relativePath release];
[super dealloc];
}
@end
It isn't MonoMac but should be the same idea.