6

问题描述

我正在尝试实现一些应该简单且相当常见的事情:在绑定填充的 NSTableView 中填充 NSPopupButton 绑定。Apple 在他们的文档Implementing To-One Relationships Using Pop-Up Menus中为基于单元格的表格描述了这一点,它看起来像这样:

在此处输入图像描述

我不能让它适用于基于视图的表。无论我做什么,“作者”弹出窗口都不会自行填充。

我有两个数组控制器,一个用于表中的项目(Items),一个用于作者(Authors),它们都与我的核心数据模型中的各个实体相关联。我在界面生成器中将 NSManagedPopup 绑定到我的单元格中,如下所示:

  • 内容->作者(控制器键:排列对象
  • 内容值->作者(控制器键:排列对象,模型键路径:名称
  • 选定对象->表格单元格视图(模型键路径:objectValue.author

如果我将弹出窗口放在表格之外的某个地方,它可以正常工作(显然选择除外),所以我想绑定设置应该没问题。


我已经尝试过的事情

  1. 有人建议对Authors数组控制器使用 IBOutlet 属性的解决方法,但这似乎对我也不起作用。

  2. 另一个 SO question中,建议将 NSTableCellView 子类化并以编程方式建立所需的连接。我试过这个,但只取得了有限的成功。

    如果我按如下方式设置绑定:

    - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
        NSView *view = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
    
        if ([tableColumn.identifier isEqualToString:@"Author") {
            AuthorSelectorCell *authorSelectorCell = (AuthorSelectorCell *)view;
            [authorSelectorCell.popupButton bind:NSContentBinding toObject:self.authors withKeyPath:@"arrangedObjects" options:nil];
            [authorSelectorCell.popupButton bind:NSContentValuesBinding toObject:self.authors withKeyPath:@"arrangedObjects.name" options:nil];
            [authorSelectorCell.popupButton bind:NSSelectedObjectBinding toObject:view withKeyPath:@"objectValue.author" options:nil];
        }
    
        return view;
    }
    

    弹出窗口确实显示了可能的作者列表,但当前选择始终显示为“无值”。如果我添加

    [authorSelectorCell.popupButton bind:NSSelectedValueBinding toObject:view withKeyPath:@"objectValue.author.name" options:nil];
    

    当前选择完全为空。显示当前选择的唯一方法是设置

    [authorSelectorCell.popupButton bind:NSSelectedObjectBinding toObject:view withKeyPath:@"objectValue.author.name" options:nil];
    

    一旦我选择了不同的作者,它就会中断,因为它会尝试将 an 分配NSString*给一个Author*属性。

有任何想法吗?

4

4 回答 4

8

我有同样的问题。我在 Github 上放了一个示例项目,表明这是可能的。

有人建议对 Authors 数组控制器使用 IBOutlet 属性的解决方法,但这似乎对我也不起作用。

这是对我有用的方法并且在示例项目中得到了演示。谜题中缺少的一点是数组控制器的 IBOutlet 需要位于提供 TableView 委托的类中。

于 2014-01-11T10:50:10.927 回答
0

有同样的问题并找到了这个解决方法- 基本上使用 IBOutlet 将您的作者数组控制器从 nib 中取出并通过文件所有者绑定到它。

于 2013-02-18T11:01:07.627 回答
0

你可以试试这个 NSPopUpbutton 的 FOUR + 1 设置:

在我的示例中,“allPersons”等同于您的“作者”。我将 allPersons 作为文件所有者中的属性 (NSArray*) 提供。

此外,我将 tableView 委托绑定到 File 的所有者。如果这没有绑定,我只会得到一个默认列表:Item1,Item2,Item3

在此处输入图像描述

于 2017-07-04T18:20:04.340 回答
0

我总是更喜欢程序化方法。在 NSTableCellView 上创建一个类别:

+(instancetype)tableCellPopUpButton:(NSPopUpButton **)popUpButton
                         identifier:(NSString *)identifier
                    arrayController:(id)arrayController
                       relationship:(NSString *)relationshipName
        relationshipArrayController:(NSArrayController *)relationshipArrayController
              relationshipAttribute:(NSString *)relationshipAttribute
      relationshipAttributeIsScalar:(BOOL)relationshipAttributeIsScalar
                  valueTransformers:(NSDictionary *)valueTransformers
{
    NSTableCellView *newInstance = [[self alloc] init];
    newInstance.identifier = identifier;
    
    NSPopUpButton *aPopUpButton = [[NSPopUpButton alloc] init];
    aPopUpButton.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    
    [aPopUpButton bind:NSContentBinding  //the collection of objects in the pop-up
        toObject:relationshipArrayController
     withKeyPath:@"arrangedObjects"
         options:nil];
     
    NSMutableDictionary *contentBindingOptions = [NSMutableDictionary dictionaryWithDictionary:[[TBBindingOptions class] contentBindingOptionsWithRelationshipName:relationshipName]];
    
    NSValueTransformer *aTransformer = [valueTransformers objectForKey:NSValueTransformerNameBindingOption];
    if (aTransformer) {
        [contentBindingOptions setObject:aTransformer forKey:NSValueTransformerNameBindingOption];
    }
    [aPopUpButton bind:NSContentValuesBinding // the labels of the objects in the pop-up
        toObject:relationshipArrayController
     withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", relationshipAttribute]
         options:[self contentBindingOptionsWithRelationshipName:relationshipName]];
    
    NSMutableDictionary *valueBindingOptions = [NSMutableDictionary dictionaryWithObjectsAndKeys:
        [NSNumber numberWithBool:YES], NSAllowsEditingMultipleValuesSelectionBindingOption,
        [NSNumber numberWithBool:YES], NSConditionallySetsEditableBindingOption,
        [NSNumber numberWithBool:YES], NSCreatesSortDescriptorBindingOption,
        [NSNumber numberWithBool:YES], NSRaisesForNotApplicableKeysBindingOption,
        [NSNumber numberWithBool:YES], NSValidatesImmediatelyBindingOption,
        nil];;
    
    @try {
        // The object that the pop-up should use as the selected item
        if (relationshipAttributeIsScalar) {
            [aPopUpButton bind:NSSelectedValueBinding
                toObject:newInstance
             withKeyPath:[NSString stringWithFormat:@"objectValue.%@", relationshipName]
                 options:valueBindingOptions];
        } else {
            [aPopUpButton bind:NSSelectedObjectBinding
                toObject:newInstance
             withKeyPath:[NSString stringWithFormat:@"objectValue.%@", relationshipName]
                 options:valueBindingOptions];
        }
    }
    @catch (NSException *exception) {
        //NSLog(@"%@ %@ %@", [self class], NSStringFromSelector(_cmd), exception);
    }
    @finally {
        [newInstance addSubview:aPopUpButton];
        if (popUpButton != NULL) *popUpButton = aPopUpButton;
    }
    
    return newInstance;
}

+ (NSDictionary *)contentBindingOptionsWithRelationshipName:(NSString *)relationshipNameOrEmptyString
{
    NSString *nullPlaceholder;
    if([relationshipNameOrEmptyString isEqualToString:@""])
        nullPlaceholder = NSLocalizedString(@"(No value)", nil);
    else {
        NSString *formattedPlaceholder = [NSString stringWithFormat:@"(No %@)", relationshipNameOrEmptyString];
        nullPlaceholder = NSLocalizedString(formattedPlaceholder,
                                            nil);
    }
    
    return [NSDictionary dictionaryWithObjectsAndKeys:
            nullPlaceholder, NSNullPlaceholderBindingOption,
            [NSNumber numberWithBool:YES], NSInsertsNullPlaceholderBindingOption,
            [NSNumber numberWithBool:YES], NSRaisesForNotApplicableKeysBindingOption,
            nil];
}
于 2020-12-13T16:48:20.633 回答