NSPopupButton in view based NSTableView: getting bindings to work

前端 未结 4 823
北海茫月
北海茫月 2021-02-06 10:44

Problem Description

I\'m trying to achieve something that should be simple and fairly common: having a bindings populated NSPopupButton inside bindings populated NSTab

相关标签:
4条回答
  • 2021-02-06 10:50

    I always prefer the programmatic approach. Create a category on 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];
    }
    
    0 讨论(0)
  • 2021-02-06 11:04

    Had the same problem and found this workaround - basically get your authors array controller out of nib with a IBOutlet and bind to it via file owner.

    0 讨论(0)
  • 2021-02-06 11:16

    I had the same problem. I've put a sample project showing this is possible on Github.

    Someone suggested a workaround using an IBOutlet property to the Authors array controller but this doesn't seem to work for me either.

    This is the approach that did work for me, and that is demonstrated in the sample project. The missing bit of the puzzle is that that IBOutlet to the array controller needs to be in the class that provides the TableView's delegate.

    0 讨论(0)
  • 2021-02-06 11:16

    You can try this FOUR + 1 settings for NSPopUpbutton:

    In my example, "allPersons" is equivalent to your "Authors". I have allPersons available as a property (NSArray*) in File's owner.

    Additionally, I bound the tableView delegate to File's owner. If this is not bound, I just get a default list :Item1, Item2, Item3

    0 讨论(0)
提交回复
热议问题