使用 NSManagedObject 子类将 NSPopupButton 绑定到 NSArrayContraller

Posted

技术标签:

【中文标题】使用 NSManagedObject 子类将 NSPopupButton 绑定到 NSArrayContraller【英文标题】:Binding an NSPopupButton to an NSArrayContraller with NSManagedObject subclasses 【发布时间】:2013-11-11 02:56:14 【问题描述】:

似乎有很多关于绑定 NSPopupButton 的问题,所以我觉得为此苦苦挣扎会好一些,但似乎没有一个能解决我的问题。

我有一个 NSManagedObject 子类,它与另一个类具有一对多的关系。假设 Foo 与 Bar 有关系,所以 Foo 有一个属性是 Bars 的 NSSet。

我创建了一个 NSArrayController 并将其 contentSet 绑定到 Foo 对象和 'bars' 键路径。

然后我将我的 NSPopupButton 的内容绑定到数组控制器的排列对象,并将它的 contentValues 绑定到数组控制器的排列对象(控制器键)和“名称”(我要显示的 Bar 上的属性)。

到目前为止,这一切都很好,但是当我尝试将 NSPopupButton 的选定对象绑定到数组控制器的选择时,NSPopupButton 显示“<_nsarraycontrollerobjectproxy keypath nspopupbutton>

Unacceptable type of value for attribute: property = "name"; desired type = NSString; given type = Bar;

我想这是有道理的,因为弹出窗口试图将“name”的字符串值设置为选定的 Bar。因此,我认为我需要绑定选定对象和选定值,但如果我设置了选定对象,XIB 将禁用选定值。

我也尝试过绑定选定的值,这一半有效(数组控制器的选择确实发生了变化),但弹出菜单中的选项不会改变以显示被取消选择的选项并隐藏新选择的选项)。

我在这里读了一篇文章:http://blog.chrisblunt.com/cocoa-bindings-and-nspopupbutton/,上面写着 NSPopupButton“NSPopUpButton 不记录用户的选择”,而是将您的选择存储在数组控制器以外的其他地方。我尝试在我的窗口中放置一个 currentBar 属性并将选择绑定到该属性,虽然我可以看到 currentBar 正在改变(因为我也绑定了另一个视图),但弹出按钮中的标签没有改变。

如果有人可以帮助我,我将非常感激。

【问题讨论】:

NSPopupButton 可以很好地用于绑定,我一直都在使用它。我会挖出一个例子并很快为你发布。 【参考方案1】:

FooBar 的东西让我很困惑,所以这是我基于真实世界对象的示例。

ExpenseTransaction 具有属性(日期、trxDescription、类别、金额)。

类别有一个属性(名称)

ExpenseTransaction.category 是与 Category 的一对一关系(换句话说,交易只能属于一个 Category)。

Category.transactions 是与 ExpenseTransaction 的 To-Many 关系(换句话说,许多交易可以属于同一个 Category)。

用于创建新事务或编辑现有事务的 UI 使用 NSPopupButton 使用 name 属性显示可用类别的列表。对于现有交易,弹出窗口将显示选定的交易类别。

Category 弹出窗口的绑定如下:

内容(Category.arrangedObjects)

内容对象 (Category.arrangedObjects) - 我们想要链接到实际类别而不是其名称,因为属性是关系而不是字符串值

内容值 (Category.arrangedObjects.name) - 我们希望名称显示在弹出列表中

选定对象(ExpenseTransaction.selection.category)

使用您的 FooBar 类比:

Category 与 ExpenseTransaction 有关系,因此 Category 有一个属性 (transactions),它是 ExpenseTransactions 的 NSSet。现在这几乎与我的安排相反,所以我真的不知道如何或为什么用 ExpenseTransaction 对象填充弹出窗口,因为弹出窗口中只有一个选定的项目可能与 Category 对象相关,而实际上你需要整个设置为相关。然而,另一种方法也可以,因为弹出窗口将包含所有 Foo 项目的列表,因此无论何时选择 Bar 项目,都可以从弹出窗口中选择相应的 Foo 项目。

希望这是有道理的。

【讨论】:

我的用例和你的有点不同。我使用弹出按钮只是为了选择可见的***对象(在我令人困惑的示例中称为 Bars),并且我创建 Foo 对象只是为了拥有一个包含所有 Bars 集合的对象,因此我有一些东西要绑定一个阵列控制器。我一直在尝试做的是将弹出窗口绑定到排列对象中的选择,因为这就是它真正的全部 - 选择。你认为这是因为我需要将选择存储到一个像你一样有逆的模型上吗? 我尝试将选择绑定到窗口中的一个属性(鉴于选择更多的是与视图而不是模型有关)但是虽然弹出窗口确实改变了该属性指向的弹出窗口本身总是说“没有价值”。 我仍然不确定我是否完全理解你的 UI 试图做什么,但你可能想要创建两个 arrayControllers,FooArray 和 BarArray。将两者都设置为实体模式并将实体名称分别设置为 Foo 和 Bar。现在要确保 BarArray 仅包含与 FooArray 中所选项目相关的项目,请将 BarArray 内容集绑定设置为 (FooArray.selection.bars),其中 bar 是多对多关系(属性)。现在 BarArray 应该只包含与所选 Foo 项目相关的 Bars 子集。 我不明白的是为什么您将弹出窗口的选定项目绑定到任何东西,因为您的模型中似乎没有对应关系。弹出窗口中选中的项目是什么意思?或者用另一种方式,用户将通过从弹出窗口中选择一个项目来实现什么,该项目包含属于以某种方式(?)选择的 Foo 项目的所有 Bar 项目。 Foo 项是如何选择的? 再次阅读上面的 cmets 似乎您拥有 Foo 对象的唯一原因是您可以将数组控制器绑定到它。为什么不能简单地创建一个 ArrayController 并将其实体设置为 Bars - 这样它将包含数据库中的所有 Bars。您不需要任何其他绑定来设置 BarsArrayController。我假设 Bars 是数据库中的一个实体(或一个托管对象)。然后将弹出窗口绑定到 BarsArrayController 并将实例变量绑定到弹出窗口 selectedObject。

以上是关于使用 NSManagedObject 子类将 NSPopupButton 绑定到 NSArrayContraller的主要内容,如果未能解决你的问题,请参考以下文章

将 NSManagedObject 转换为子类类型的问题

将 NSManagedObject 转换为子类返回 nil

如何将 NSManagedObject 的 NSKeyedUnarchive 子类导入核心数据?

NSManagedObject 子类属性

NSManagedObject 子类模拟

托管对象之外的 NSManagedObject 子类作为普通对象