2

用自定义单元格填充 NSTableView 的最佳方法是什么?

在填充标准数据时,我总是使用 Cocoa 绑定,而在使用自定义单元格填充表格时,我总是使用数据源。我想知道是否有一种方法可以混合这两个概念以获得最佳设计。

遗憾的是,使用 Xcode 3(以及因此,IBPlugins)不是一种选择。

4

1 回答 1

3

我个人不会混合绑定数据和数据源。我没有遇到什么,但试图这样做的痛苦。不过,我确实有几种方法可能会对您有所帮助。

我能够做的一件事是在 IB 中设置一个自定义单元格类,它是IB 知道的其中一个单元格的子类,然后覆盖您需要的任何内容以使其执行您想要的操作。但首先是一些背景知识,以及一些错过的尝试:

当绑定基于单元格的 NSTableViews 时,您通常在列本身而不是列中的单元格上设置绑定。如果您在表格列中使用自定义 NSCell 子类,您会注意到该value列上不再提供类似的绑定,这与单元格是 NSTextFieldCell 不同。我试图通过将value绑定设置为 NSTextFieldCell,然后切换出单元格来对 IB 进行排序——绑定仍然出现在绑定检查器中,但它总是在运行时崩溃并出现以下错误:[<NSTableColumn 0x10252e910> valueForUndefinedKey:]: this class is not key value coding-compliant for the key value.

这让我想到了对 IB 知道如何绑定的单元之一进行子类化的方法。我创建了一个 NSTextFieldCell 的子类,深入到表格列中的“文本字段单元格 - 文本单元格”,然后在 Identity Inspector 中设置我的自定义子类。我能够确认绑定仍然有效,并且 IB 仍然将其视为 NSTextFieldCell。从那里,我可以在我的自定义单元类中覆盖我想要的任何方法并获得自定义行为。我没有理由相信图像单元也不能做到这一点。自然,这是一种虚假的方法,但取决于您的自定义单元格的“自定义”程度,它可能优于编写一堆自定义代码来连接数据源。

我在进一步的实验中发现这是一个“IB 问题”,而不是真正的 NSTableView/绑定问题。还有另一种很好的解决方法。

假设您想使用一个自定义单元,并且您想将它绑定到某个任意模型对象。您将 NSTableColumn 值绑定绑定到 NSArrayController ,该 NSArrayController 正在出售自定义模型对象列表,每个对象都有一个属性,调用它dataForCustomCell返回自定义单元格需要执行的任何操作。您将设置一个 TextFieldCell 列(如 IB 中的默认值),然后将valueNSTableColumn 的绑定绑定到 Array Controller >arrangedObjects并输入模型键路径dataForCustomCell。此时,假设dataForCustomCell实现 NSCopying 返回的对象(如果没有,您的应用程序将崩溃,但此时这并不真正相关)如果您运行您的应用程序,您会看到 NSTextFieldCell 将调用- (NSString*)description返回的对象经过dataForCustomCell并将该文本放入单元格中。

现在是有趣的部分:-awakeFromNib有时在您拥有的对象(NSView、NSViewController 等)中,替换 dataCell(如果您愿意,还可以替换 headerCell),如下所示:

- (void)awakeFromNib
{
    [super awakeFromNib];
    // Assuming you've got your NSTableView plugged into an IBOutlet property called table
    NSTableColumn* col = [[self.table tableColumns] objectAtIndex:0];
    col.dataCell = [[[MYCustomCell alloc] init] autorelease];
}

由于绑定位于 NSTableColumn 而不是单元格本身,因此您可以换出单元格而不必担心重新连接任何绑定。在您的自定义单元类中,覆盖-(void)setObjectValue:,您将在运行时从绑定机制获得调用,将来自dataForCustomCell模型对象上的属性的对象推入与表的当前绘制行相对应。(您还会收到一个为每个单元格传入 nil 的调用,但忽略它或将其传递给 super 似乎是安全的。)

这种方法的一个缺点是您只能获得 NSTextFieldCell 具有的一个“值”绑定。-setObjectValue:解决方法是将该值绑定绑定到模型中更大/更高的“颗粒”,然后在需要时在您的实现中向下钻取并扇出多个值。

它并不完美,但它是“几行代码”的修复,而不是“无数行代码”的修复。

或者,假设您的目标是相当新的 MacOS 版本,您也可以使用基于视图的 NSTableViews。它们非常好,并且以比基于 NSCell 的表更明智的方式处理绑定。这是一种完全不同的做事方式,所以很难说你的任务将如何映射到它。Apple 开发者网站上有一段很棒的视频,可以让您快速了解基于 NSView 的 NSTableView。

于 2012-01-14T18:09:14.553 回答