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.
Related
I cannot figure a way to enable/disable editing in view based NSTableViews using cocoa bindings.
I mean, I can perfectly enable/disable editing in a separate NSTextField, by binding it's "editable" attribute to a file's owner property such as
#property BOOL canModify;
(bind to: file's owner)
(Model Key Path: self.canModify)
But if I do exactly the same with a NSTextField in a view based TableView the binding seems to be totally ignored.
Also to be noticed that I can populate the table via bindings/array controllers so it's quite strange that the stuff doesn't work only for the "editable" property.
Thank you in advance
No. There's no problem in Apple's implementation of File's owner bindings for tablecellviews. I simply overlooked an IB warning.
"... Objects inside view-based cells may only be connected to the tableview's delegate."
I did set the "delegate" outlet of the TableView to my WindowController (implementing the "delegate protocol) and everything is working fine, without any double double double passages over table Cell's objectValues.
The name of your property and the key path of your binding don't match, although maybe that's just a typo: canModify vs. canModyfy ("i" vs. "y").
The editable binding should work just fine. You should check your other bindings, such as the value binding, to see if it has the Conditionally Sets Editable binding option enabled. Annoyingly, this option is enabled by default.
Lastly, you haven't explained in which NIB you're defining your cell views. Are they defined in the same NIB as the table view itself, or are they in a separate NIB? That would affect which object is File's Owner.
Even when table cell views are defined inside the same NIB as the table view, I believe they are encoded as a NIB-within-a-NIB. That is, each table cell view subhierarchy is actually encoded into a NIB blob and that NIB blob is archived into the parent NIB. When the table cell view sub-NIB is loaded, the table view's delegate is usually supplied as its owner. So, binding to File's Owner may not have the effect you expect.
For table cell views, you usually bind the subviews (like an NSTextField) to the table cell view itself, keyed off of the objectValue property.
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 just created my first view-based NSTableView in Interface Builder and I've correctly set up the data source and the bindings to update the views in the tableview. Each view has two labels and a NSProgressIndicator. Updating the progress indicator through the bindings and the data source works perfectly, but I'd like to change its state from determinate to indeterminate at some time. As my NSTableCellView subclass has access to the progress indicator, how can I get access to the cell view at a given row index? I've tried calling viewAtColumn:row:makeIfNecessary: on the tableview with both NO and YES for the makeIfNecessary argument, but neither seems to work.
Solution 1: In your NSTableCellView subclass add a property (IBOutlet) for your NSProgressIndicator control. Wire it in IB to set the property when the view is loaded. You can then access the progress control in your cell view subclass by using the property.
Solution 2: In IB give your NSProgressIndicator a unique integer tag. In your cell view subclass use [self viewWithTag:] to get the object.
I am not sure about the answer to your main question but you can bind the indeterminate state as well. In IB Is Indeterminate is listed in the Parameters section.
I made a Cocoa application that has an NSTableView, an NSTextField, and an NSButton. The user enters text into the text field and clicks the button. When the user does this, I want the text in the textfield to be placed in the NSTableView. I find that I can't even bind an IBOutlet to a cell in the NSTableView. What should be done?
The Model-View-Controller pattern, which is used extensively in Cocoa is your friend here.
What you need to do is to bind the NSTableView to an array (The model). Then configure the button so that a click tells the controller to add the content of the text field to the array and if the bindings are set up correctly the NSTableView (The View) will be updated.
What I think you need to do is make a class, AppController for instance which will be your data source and the delegate of the NSTableView. So you need the following.
Two IBOutlets (one for the NSTextField and one for the NSTableView)
An IBAction for the NSButton.
Make those connections in Interface Builder.
Remember to use the mandatory delegate methods (there are two of them) so you can add the data from your data source (usually a collection class..an array, dictionary...etc.
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).