Bindings: changing model changes some views but not others (NSTableColumn)

  • Hi all,

    I have an NSTableColumn bound like so:

    bind to: AppController (NSObject subclass instantiated in the nib)
    controller key: n/a
    model key path: polarisMaster.polaris
    ControlsController.selection.toolsController.arrangedObjects.name

    and an NSTextField bound like so:

    bind to: AppController (NSObject subclass instantiated in the nib)
    controller key: n/a
    model key path: polarisMaster.polaris
    ControlsController.selection.toolsController.selection.name

    Most everything works fine, except... if I call the setName: method on
    one of the model objects.  Changing the model should update the views
    via KVO/KVC, right?  The NSTextField does indeed update.  But the
    tableview does not!  (Unless I resize the window or click somewhere in
    the table.)

    What could I be doing wrong here?  I'm stumped.

    mmalc's ToDos example is similar and does not have this problem.  One
    difference is that I create my NSArrayControllers programatically
    instead of having them in the NIB.

    Thanks for any help!

    --
    ____________________________________________________________
    Sean McBride, B. Eng                <sean...>
    Rogue Research                        www.rogue-research.com
    Mac Software Developer              Montréal, Québec, Canada
  • On Nov 29, 2006, at 11:19 AM, Sean McBride wrote:

    > I have an NSTableColumn bound like so:
    >
    > bind to: AppController (NSObject subclass instantiated in the nib)
    > controller key: n/a
    > model key path: polarisMaster.polaris
    > ControlsController.selection.toolsController.arrangedObjects.name

    Have you tried binding to an array controller directly in the NIB?

        - Scott
  • On 2006-11-29 13:57, Scott Stevenson said:

    >> I have an NSTableColumn bound like so:
    >>
    >> bind to: AppController (NSObject subclass instantiated in the nib)
    >> controller key: n/a
    >> model key path: polarisMaster.polaris
    >> ControlsController.selection.toolsController.arrangedObjects.name
    >
    > Have you tried binding to an array controller directly in the NIB?

    Scott, you are definitely on to something!!!

    I took mmalc's ToDos sample and gutted it to be simpler.  It still
    worked.  Then, instead of using the NSArrayController in the NIB I
    created one programatically in the MyDocument init method.  I have KVC
    accessors in MyDocument:

    - (NSArrayController *)catController;
    - (void)setCatController:(NSArrayController *)aCatController;

    Then I change the NSTableColumn binding from:

    bind to: Categories (an NSArrayController in the NIB)
    controller key: arrangedObjects
    model key path: title

    to

    bind to: File's Owner (MyDocument)
    controller key: n/a
    model key path: catController.arrangedObjects.title

    And changed other bindings analogously.  Additionally, I had to bind the
    NSTableView's 'content', 'selectionIndexes', and 'sortDescriptors'
    bindings as it seems IB does this behind the scenes when the controller
    is in the NIB, but not otherwise.

    And now I have the same problem as my app!  That is, if I change a model
    object, the tableview does not update unless I resize the window or
    click the tableview.  It's as if tableview has simply forgot to redraw.
    Text fields update fine, but not table columns.

    Shouldn't what I did work?

    Thanks,

    --
    ____________________________________________________________
    Sean McBride, B. Eng                <sean...>
    Rogue Research                        www.rogue-research.com
    Mac Software Developer              Montréal, Québec, Canada
  • On Nov 30, 2006, at 9:49 AM, Sean McBride wrote:

    > And now I have the same problem as my app!  That is, if I change a
    > model
    > object, the tableview does not update unless I resize the window or
    > click the tableview.  It's as if tableview has simply forgot to
    > redraw.
    > Text fields update fine, but not table columns.
    >
    > Shouldn't what I did work?

    It's hard to say because we're only seeing little snippets of the
    project and there are a lot of subtleties to the equation.

    Is there some reason you need to create the NSArrayController
    programmatically? The setup you have with a table column binding down
    through MyDocument to reach an NSArrayController is a bit
    unconventional. Why not just add it in IB?

        - Scott
  • On 2006-11-30 17:16, Scott Stevenson said:

    >> And now I have the same problem as my app!  That is, if I change a
    >> model
    >> object, the tableview does not update unless I resize the window or
    >> click the tableview.  It's as if tableview has simply forgot to
    >> redraw.
    >> Text fields update fine, but not table columns.
    >>
    >> Shouldn't what I did work?
    >
    > It's hard to say because we're only seeing little snippets of the
    > project and there are a lot of subtleties to the equation.

    True enough!  If you or anyone else would like to take 2 minutes to
    check it out, I've distilled it down to something very simple (I know
    your time is precious).  No code changes are needed, you just use one of
    two versions of the NIB.  One NIB uses an NSArrayController in the NIB,
    the other uses an NSArrayControllor created programatically and accessed
    via File's Owner.  This screenshot shows the differences in bindings:
    <http://www.rogue-research.com/vtk/BindingComparisions.png>

    The zipped up project is here:
    <http://www.rogue-research.com/vtk/NSTableColumnNotUpdating.zip>

    > Is there some reason you need to create the NSArrayController
    > programmatically? The setup you have with a table column binding down
    > through MyDocument to reach an NSArrayController is a bit
    > unconventional. Why not just add it in IB?

    Alas one reason is that the code is used by an old PowerPlant
    application, and doesn't have any NIBs at all. :)  I suppose I could add
    a NIB, but what's so magical about NIBs that array controllers have to
    exist there?

    Thanks,

    --
    ____________________________________________________________
    Sean McBride, B. Eng                <sean...>
    Rogue Research                        www.rogue-research.com
    Mac Software Developer              Montréal, Québec, Canada
  • On Dec 1, 2006, at 11:01 AM, Sean McBride wrote:

    > True enough!  If you or anyone else would like to take 2 minutes to
    > check it out, I've distilled it down to something very simple (I know
    > your time is precious).  No code changes are needed, you just use
    > one of
    > two versions of the NIB.  One NIB uses an NSArrayController in the
    > NIB,
    > the other uses an NSArrayControllor created programatically and
    > accessed
    > via File's Owner.  This screenshot shows the differences in bindings:
    > <http://www.rogue-research.com/vtk/BindingComparisions.png>
    >
    > The zipped up project is here:
    > <http://www.rogue-research.com/vtk/NSTableColumnNotUpdating.zip>

    You certainly win the prize for the best question asking. The project
    and screenshots (and included instructions) made this easier by miles.

    I mucked around with this for a while, and could probably figure it
    out given enough time, but I'm sure somebody with Cocoa source code
    could do it much faster. If you you have an ADC tech support
    incident, this would be a good time to use it.

    Something interesting is that if you unbind the table view itself
    (just leaving the columns bound), you don't get any row data at all.
    That's clearly wrong, so it suggests what you're seeing is just a
    reflection of something more fundamental.

    It wouldn't surprise me if this was a garden variety bug that few
    people ever encounter. This is the first time I've seen a
    configuration like this, though I think I understand the rationale.

    One other stab in the dark thing you could try:

    Bind the table columns directly to the array controller in code. I
    suspect all of this has something to do with the fact that the table
    columns don't realize they're getting their data from an array
    controller. All they know is they're somehow getting this data from
    some array somewhere, which happens to have "arrangedObjects" in the
    name. That may not even be a supported configuration.

    If you bind directly to an array controller, the table columns may
    snap to life, addressing the underlying issue. It's amazing how many
    bindings issues are solved by breaking the bindings in multiple steps
    instead of trying to bind to one long keypath.

    If that does work, please post a follow-up.

        - Scott
  • On 2006-12-01 20:32, Scott Stevenson said:

    > I mucked around with this for a while, and could probably figure it
    > out given enough time, but I'm sure somebody with Cocoa source code
    > could do it much faster. If you you have an ADC tech support
    > incident, this would be a good time to use it.

    Well, I've filed <rdar://4862378>.  I'm glad you find it odd too,
    whenever I have weirdo bindings problems like this I assume it's me
    that's misunderstood something.  Thanks for taking the time to take a
    look at all this!

    > Something interesting is that if you unbind the table view itself
    > (just leaving the columns bound), you don't get any row data at all.
    > That's clearly wrong, so it suggests what you're seeing is just a
    > reflection of something more fundamental.

    I'm not so sure about that.  It might be 'expected behaviour'.  I
    believe when you bind NSTableColumns to a NSController-subclass in a NIB
    that 'binding magic' kicks in and does the NSTableView bindings
    automagically.  mmalc hints to it here:

    <http://homepage.mac.com/mmalc/CocoaExamples/controllers.html>
    "Typically you only need to bind each table column value binding to the
    arranged objects of an array controller. When you do this, behind the
    scenes, all three table view content bindings are automatically 'hooked
    up' for you. It is only when you need to change these three default
    content bindings that you need to visit the table view's bindings."

    > One other stab in the dark thing you could try:
    >
    > Bind the table columns directly to the array controller in code. I
    > suspect all of this has something to do with the fact that the table
    > columns don't realize they're getting their data from an array
    > controller. All they know is they're somehow getting this data from
    > some array somewhere, which happens to have "arrangedObjects" in the
    > name. That may not even be a supported configuration.
    >
    > If you bind directly to an array controller, the table columns may
    > snap to life, addressing the underlying issue. It's amazing how many
    > bindings issues are solved by breaking the bindings in multiple steps
    > instead of trying to bind to one long keypath.

    I tried binding programatically the same way as it's wired in IB, that is:

    [titleColumn bind:@"value" toObject:self
      withKeyPath:@"catController.arrangedObjects.title"
      options:nil];

    Same result (makes sense).  Then I tried what you suggested, that is:

    NSArrayController*  controller = [self catController];
    [titleColumn bind:@"value" toObject:controller
      withKeyPath:@"arrangedObjects.title" options:nil];

    And now things work great!

    I guess one just can't reliably bind via File's Owner, though I thought
    we were supposed to be able to...

    --
    ____________________________________________________________
    Sean McBride, B. Eng                <sean...>
    Rogue Research                        www.rogue-research.com
    Mac Software Developer              Montréal, Québec, Canada
previous month november 2006 next month
MTWTFSS
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
Go to today