NSPopupButton在基于NSTableView的视图中:使绑定工作

时间:2013-02-05 13:43:41

标签: cocoa nstableview cocoa-bindings nspopupbutton

问题描述

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

enter image description here

我无法让这个用于基于视图的表。无论我做什么,“作者”弹出窗口都不会填充。

我有两个阵列控制器,一个用于表格中的项目(项目),另一个用于作者(作者),两者都与我的相应实体相关联核心数据模型。我在我的单元格中绑定NSManagedPopup,如下所示:在界面构建器中:

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

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


我已经尝试过的事情

  1. 有人向作者数组控制器建议workaround using an IBOutlet property,但这似乎对我不起作用。

  2. another 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];
    

    一旦我选择其他作者就会中断,因为它会尝试将NSString*分配给Author*属性。

  3. 任何想法?

4 个答案:

答案 0 :(得分:8)

我遇到了同样的问题。我已经放了一个sample project表明这可以在Github上使用。

  

有人向作者提出了使用IBOutlet属性的解决方法   数组控制器,但这似乎对我不起作用。

这是 为我工作的方法,并在sample project中进行了演示。这个难题的缺失是,数组控制器的IBOutlet需要在提供TableView委托的类中。

答案 1 :(得分:0)

遇到同样的问题并发现this workaround - 基本上将你的作者数组控制器从带有IBOutlet的nib中取出并通过文件所有者绑定到它。

答案 2 :(得分:0)

您可以尝试NSPopUpbutton的这四个设置:

在我的例子中,“allPersons”相当于你的“作者”。 我在文件所有者中将allPersons作为属性(NSArray *)提供。

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

enter image description here

答案 3 :(得分: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];
}