19

我想要完成的似乎应该相当简单。我在这里放置了一个示例项目。

我有一个 NSArrayController 填充了一个 NSDictionaries 数组。

[[self controller] addObject:@{ @"name" : @"itemA", @"part" : @"partA" }];
[[self controller] addObject:@{ @"name" : @"itemB", @"part" : @"partB" }];
[[self controller] addObject:@{ @"name" : @"itemC", @"part" : @"partC" }];

我正在使用基于“名称”键的此数组中的项目填充 NSPopupButton。这可以通过以下绑定轻松完成

绑定

然后,我想根据 NSPopupButton 的当前选择使用“部分”键中的文本填充 NSTextField。我已经设置了以下绑定:

文本字段绑定

单独使用这些绑定,文本字段会显示“partC”。

初始显示

但是,如果我更改 NSPopupMenu 的值,文本字段显示的内容不会改变。

我认为这只是在 NSPopupButton 上设置“选定对象”绑定的问题

选定对象

但这行不通。出于某种奇怪的原因,我最终在菜单中使用了代理对象(提供了奖励的原因)。

窗口2

那么,我需要做什么才能完成这项工作?

4

1 回答 1

58

在这种情况下不要使用“选定对象”。将弹出窗口的“选定索引”绑定到 NSArrayController 的selectionIndex控制器键。在您的示例项目上进行了尝试,并且可以正常工作。

编辑:

您问为什么使用selectionIndexover是合适的selectedObject。首先是一些背景:

绑定弹出菜单时,您可以绑定三个虚拟“集合”:Content是抽象的“菜单中应包含的内容列表”——您必须始终指定Content。如果您既不指定Content Objects也不指定Content Values,则绑定到Content的值的集合将用作“对象”,其-description方法返回的字符串将用作“值”。换句话说,内容值是弹出窗口中显示的字符串,内容对象是它们对应的东西(可能不是字符串,也可能没有-description适合在弹出窗口中生成文本的方法)。这里需要意识到的重要一点是,这里可能存在三个不同的“虚拟数组”:内容数组、内容对象数组(可能不同)和内容值数组(也可能不同)。它们都将具有相同数量的值,并且通常,内容对象内容值将是内容数组中相应项目的函数(在数学意义上)。

下一件重要的事情是,NSArrayController生活中的一部分目的是跟踪用户的选择。在弹出窗口的情况下,这只是轻微(如果有的话)有趣,但在NSTableView. 在内部,NSArrayController通过保持包含在任何给定时间选择的Content数组NSIndexSet中的索引来跟踪这一点。从那里,为方便起见,选择状态以几种不同的方式显示:

  • selectionIndexes如上所述 -包含Content数组NSIndexSet中所选项目的索引
  • selectionIndex对于不支持多选的应用程序来说是一个方便的选项。可以认为它等价于arrayController.selectionIndexes.firstIndex
  • selectedObject在单选情况下也很有用,并且在概念上对应于ContentObjectsArray[arrayController.selectionIndexes.firstIndex]
  • selection返回一个特殊对象(对消费者不透明),代理读取和写回数组控制器的内容数组中的底层对象(或多选情况下的对象) 。它的存在是为了在多个选择情况下一次编辑多个对象,并为其他特殊情况提供支持。(你应该认为这个属性是只读的;因为它的类型对消费者来说是不透明的,所以你永远无法创建一个合适的新值来写入它。像这样的调用是有意义的-[arrayController.selection setValue: myObject forKey: @"modelKey"],但是像这样的调用是没有意义的-[arrayController setValue: myObject forKey: @"selection"]

有了对属性的理解selection,让我们退后一步,看看为什么在这种情况下使用它不是正确的。 尝试变得聪明:您已经通过ContentContent Values绑定NSPopUpButton为其提供了应该在菜单中的内容列表。然后你还告诉它你想将它的Selected Object绑定到'属性。您可能认为这是一个“只写”绑定——即“亲爱的弹出窗口,请接受用户的选择并将其推送到 arrayController”,但绑定实际上是双向的。因此,当绑定刷新时,弹出窗口首先使用内容/内容值中的所有项目填充菜单NSArrayControllerselection绑定,然后它说,“哦,你说 at 的值arrayController.selection是我的Selected Object。这很奇怪 - 它不在与我的Content/Content Values绑定绑定的事物列表中。我最好将它添加到列表中你!我会通过调用-description它来做到这一点,然后将那个字符串插入菜单中。但是您从Selected Object绑定中获得的对象是上述不透明的选择对象(您可以从结果中看到它属于 class _NSControllerObjectProxy,这是一个私有到 AppKit 的类,如前导下划线所示)。

总之,这就是为什么将弹出窗口的Selected Object绑定绑定到数组控制器的selection控制器键是错误的做法。遗憾的是,但我相信您已经发现,Cocoa 绑定的文档才刚刚开始,所以不要难过。几年来,我几乎每天都在使用 Cocoa 绑定,在一个大型项目中,我仍然觉得有很多用例我还没有完全理解。

于 2013-02-18T12:41:25.843 回答