How do I bind the enabled state of an NSMenuItem to an NSArrayController's selection? I've tried binding the item's enabled state to the controller's selectedObjects or selectedIndexes and in neither case is the menuitem ever enabled when there are selections. In IB, I unchecked the "enable" checkbox. I simply want the NSMenuItem to be enabled when there are selections in the table. My table allows for multiple selection and I also use a button which is bound to selectedObjects.#count and the button enables/disables as expected, so I thought using the same keypath would work for the menuitem as well, but nope. This can't be difficult as I can't find an answer via google, so I figure it must be simple.
Thanks
The enabled binding has to get a BOOL value, and unfortunately won't just treat any old object as a boolean True. Fortunately, however, NSValueTransformer makes it easy to do so. There's a couple of constants named in the NSValueTransformer Class Reference which you can use in the bindings pane in IB.
In your case, you can bind the Model Key Path to "selectedObjects" and enter "NSIsNotNil" in the Value Transformer field. The transformer gives the binding the BOOL value it needs.
Related
I have an NSOutlineView that is bound to a NSTreeController. The details are like this:
the treeController has class mode, and CommonListData as the Class Name, which has a "children" property
the treeController also has "content array" bound to File's Owner's "headersArray" (of type NSArray). The "headersArray" is an array of CommonListData items
the NSOutlineView has bindings for "Content" to the treeController's arrangedObjects
the view-based outlineView is designed in Interface Builder, with each cell view has lots of elements. Each element (labels, images etc) have 'value' bindings to the NSTableCellView with the relevant objectValue.xxx model key paths
The setup is fairly simple, and it all works fine in adding and deleting objects. But the problem is that it doesn't use any of the NSOutlineView / NSTableView animations when adding or removing items from the outline view. The table just reloads itself if I add or remove any element to the treeController, or directly to the headersArray's children objects. I'm not sure if that is a limitation with Cocoa Bindings or what.
In any case, I am consider whether I can disable all the bindings and do this manually. The only drawback is that the NSOutlineView cell views have complicated elements on them, and I don't want to have to map the view elements to the data in code. Ideally it should keep the bindings in the NSTableViewCell.
So my question is:
Is it possible to keep the bindings within Interface Builder in a NSTableCellView, but not bind the content to the treeController? Or is there an alternative to binding "arrangedObjects", such that adding and removing data from the NSTreeController doesn't trigger an update to the UI?
It would help to have some more control over the bindings, so that I can trigger the animations correctly, and not have it just jump around with every update.
I believe the bindings of the views within the cell view are independent of the bindings of the outline view's content. Whether the outline view uses bindings or not, it eventually sets the objectValue property of the cell view. So long as that's done in a KVO-compliant manner (which it is), any bindings to that property will work.
I've got a simple master-detail project with an array of class instances, an array controller providing a selection of a specific class instance, and an NSTableView presenting the array and the selection. My class has an NSString property, and when I bind it to to an NSTextField, everything works great.
However, when I bind the same property to the Value Path field of an NSTextView, it behaves very erratically:
Selecting among entries in the NSTableView causes no change in the NSTextView, even though the selected objects have different values for the bound property.
Nothing typed into the NSTextView is copied into the property of the selection.
The only apparent effect of the binding is that clearing the selection in the NSTableView (e.g., clicking below all of the entries) causes the contents of the NSTextView to vanish.
Any ideas?
The valuePath binding is for file paths. The value binding is for strings; there're also data (RTF/RTFD) and attributedString bindings.
I would like to bind the boolean enabled property of an NSTextField to the state of an NSButton. I already tried adding a custom NSValueTransformer that transforms the state of the NSButton into NSNumber. However, in that scenario the text fields are disabled all the time for some reason. My second approach: To bad fails also since NSValueTransformer does not offer return primitives types such as BOOL.
Example:
The screenshot shows an example in which the text fields are disabled because the checkbox has the state NSOnState. I also would like to bind the labels to this state.
Further, it would be convenient, if I could set a "disabled text" in Interface Builder. In the above example I set the text in the associated class.
Edit:
I set self.anonymousLoginCheckbox.state as the Model Key Path for the enabled property of the account text field. Similar for the password text field. However, it does not work.
Update:
I created an example project available on GitHub showing the implementation kindly described by Nicolas Bachschmidt.
NSButton isn't KVO compliant for the key state. Cocoa Bindings require the observed object to emit notifications when the observed property changes. As NSButton's state is just a wrapper for its cell's state, -[NSButton setState:] method (and the automatic KVO notifications) isn't invoked when the user click the button (but -[NSCell setState:] is). If you set the model key path to self.anonymousLoginCheckbox.cell.state, it will work.
Is it possible to bind the representedObject property of a NSViewController to an NSArrayController's selection property (which is a NSManagedObject)?
[self.ressourcesViewController bind:#"representedObject" toObject:self.ressourcesController withKeyPath:#"selection" options:nil];
This always gives me the no selection placeholder for some reason!
this is possible by using the keypath selectedObjects.#lastObject !
Although i don't know how standard conform this is, since bindings are meant to synchronize view objects to controller objects. What i do is synchronizing 2 controller objects..
On the other side, using bindings just saves some code, needed instead to implement it manually via KVO and KVC.
This question is similar to this one: How do I use an NSFormatter subclass with an NSPopUpButton
As mentioned in that question, it seems like the 'formatter' used by the cell of a NSPopUpButton doesn't seem to work. I'm wondering if this is expected, or if there is actually a purpose to setting the formatter of a NSPopUpButton.
Right now, I have a NSPopUpButton whose "Content Objects" are bound to the arrangedObjects of a NSArrayController whose "Content Array" is a NSArray of NSNumbers. Setting the formatter of the NSPopUpButton cell to a simple NSNumberFormatter which formats NSNumbers in a currency format doesn't work; the pop up menu displays the numbers un-formatted.
I'm wondering how I can format strings displayed in the pop up menu of an NSPopUpButton? I feel like this should be fairly straight-forward; having to use a value transformer, or a special value for the display path, seems like overkill and should be easier.
Thanks in advance.
If the cell won't honor the formatter, then you could provide an alternative property like -formattedCost as opposed to -cost. Nothing fancy is needed since a popup button's menu items are not user-editable.
Your -formattedCost property would use a shared NSNumberFormatter instance and return the properly-formatted string of -cost.
- (NSString *)formattedCost
{
return [mySharedCurrencyFormatter stringFromNumber:[self cost]];
}
The "formattedCost" property is what you'd bind to for display. Additional caveats: you'll want to register the "formattedCost" key as being dependent on the "cost" key. That way, when costs are changed, your popup will update (because that triggers "formattedCost" to change as well).