【问题标题】:NSPopupButton in view based NSTableView: getting bindings to work基于视图的 NSTableView 中的 NSPopupButton:让绑定工作
【发布时间】:2013-02-05 13:43:41
【问题描述】:

问题描述

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

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

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

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

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


我已经尝试过的事情

  1. 有人向 Authors 数组控制器建议了 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* 属性。

有什么想法吗?

【问题讨论】:

  • 您找到解决方案了吗?我也有同样的问题。

标签: cocoa nstableview cocoa-bindings nspopupbutton


【解决方案1】:

我遇到了同样的问题。我在 Github 上放了一个 sample project 表明这是可能的。

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

这是确实为我工作的方法,这在sample project 中得到了展示。谜题中缺少的一点是数组控制器的 IBOutlet 需要在提供 TableView 委托的类中。

【讨论】:

  • 哦,伙计,这让我快疯了,感谢您的解决方案。绑定到我的文件所有者的数组控制器 IBOutlet(而不是同一个笔尖中的数组控制器对象!)有效。把我当成一个bug,有人提交了雷达吗?
  • 感谢您引导我找到解决方案。另一个关键信息是将弹出窗口的选定对象绑定到表格单元格视图(Model Key Path = objectValue.propertyName);原始问题中提到了这一点,但大多数教程似乎并没有充分强调这一点。 (Apple 的文章 Populating a Table View Using Cocoa Bindings 确实提到了这一点,但不是在弹出菜单的上下文中。)
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      我总是更喜欢程序化方法。在 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];
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-14
        • 1970-01-01
        • 2013-10-04
        • 1970-01-01
        • 1970-01-01
        • 2014-01-14
        相关资源
        最近更新 更多