Re: Binding to currently selected object in a list?

2009-10-10 Thread Ken Thomases

On Oct 9, 2009, at 5:08 PM, A B wrote:

Is there a way to bind an ivar to the currently selected object of a  
list which is being represented in an NSTableView via bindings?   
Unfortunately there does not seem to be a selectedObject key  
(though there is one for selectedObjects).  Binding to the  
controller's selection doesn't really work as I'd expect and even  
if it did, I'd only be getting back a proxy object - which negates  
the purpose for which I want to use it, which is to call methods on  
the object.  I had put in a hack which observes changes in  
selection, gets the selectedObjects list, checks for a count  0,  
grabs the first and stuffs it into the ivar, etc. but not only does  
that feel really hackish, but doesn't always work.


This would seem to be a pretty simple thing to want to do (i.e.  
present a list of objects, do things to/with the currently selected  
object) but I'm at somewhat of a loss to understand what I'm doing  
wrong.


There's something just like this for NSPopUpButton.  You bind its  
'content' (and possibly 'contentObjects') binding to an indexed  
collection property of the controller.  Then you bind its  
'selectedObject' binding to a to-one property of the controller.  When  
the pop-up is first set up, it displays the selected object as  
originally set on the controller's to-one property.  Then, as the user  
selects items from the pop-up, the newly selected object is passed to  
the setter for that to-one property.


Strangely, there's nothing quite like that for NSArrayController.

I think the best you can do is to bind the array controller's  
selectionIndexes binding to an attribute of your coordinating  
controller.  (For illustration purposes, I'll call this attribute  
property selectedWidgetIndexes.)  Then that coordinating controller  
can have a selectedWidget to-one property which is set up to reflect  
the object which is selected in the array controller.


One way is to make the selectedWidget property computed-on-the-fly  
based on the selection indexes:


+(NSSet*)keyPathsForValuesAffectingSelectedWidget
{
return [NSSet setWithObject:@selectedWidgetIndexes];
}

-(Widget*)selectedWidget
{
if (![self.selectedWidgetIndexes count])
return nil;
	return [self.widgets objectAtIndex:[self.selectedWidgetIndexes  
firstIndex]];

}

In this scenario, you don't actually have an ivar backing the  
selectedWidget property.  It's completely based off of the  
selectedWidgetIndexes property and the widgets to-many property.   
(The widgets property is assumed to be the indexed collection property  
that the array controller is representing.  The selectedWidgetIndexes  
property can be a typical @synthesized copy property.)


Another approach is to implement the setter for selectedWidgetIndexes  
and use that to update the selectedWidget property directly.  In this  
case, selectedWidget isn't computed on the fly, but is actually held  
(cached) in an ivar:


-(void)setSelectedWidgetIndexes(NSIndexSet*)newSelectedWidgetIndexes
{
if (![selectedWidgetIndexes isEqual:newSelectedWidgetIndexes])
{
[selectedWidgetIndexes release];
selectedWidgetIndexes = [newSelectedWidgetIndexes copy];
if ([selectedWidgetIndexes count])
			self.selectedWidget = [self.widgets objectAtIndex: 
[selectedWidgetIndexes firstIndex]];

else
self.selectedWidget = nil;
}
}

You don't need +keyPathsForValuesAffectingSelectedWidget since you're  
going through the setter for the selectedWidget property.  The  
selectedWidget property can be a typical @synthesized retain property.


By the way, notice that all of this discussion is in terms of the  
array controller and the coordinating controller.  No mention of the  
table view because it's not directly relevant.  The MVC design pattern  
in action.  ;)


Regards,
Ken

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Binding to currently selected object in a list?

2009-10-10 Thread A B
 Ken,
Thank you for the well-expressed response.  I understand both options as you've 
explained them and will try them both to see which ones I end up having a 
better feel for.  I may have to go for the second example as I think that it 
will get executed in a more deterministic order earlier - which is something 
that I will need to be reasonably assured of as the 'selectedWidget' value is 
one that is used by other KVO-triggered actions and that therefore lack of 
guaranteed order of setting can end up causing me problems.

On Friday, October 09, 2009, at 11:57PM, Ken Thomases k...@codeweavers.com 
wrote:
On Oct 9, 2009, at 5:08 PM, A B wrote:

 Is there a way to bind an ivar to the currently selected object of a  
 list which is being represented in an NSTableView via bindings?   
 Unfortunately there does not seem to be a selectedObject key  
 (though there is one for selectedObjects).  Binding to the  
 controller's selection doesn't really work as I'd expect and even  
 if it did, I'd only be getting back a proxy object - which negates  
 the purpose for which I want to use it, which is to call methods on  
 the object.  I had put in a hack which observes changes in  
 selection, gets the selectedObjects list, checks for a count  0,  
 grabs the first and stuffs it into the ivar, etc. but not only does  
 that feel really hackish, but doesn't always work.

 This would seem to be a pretty simple thing to want to do (i.e.  
 present a list of objects, do things to/with the currently selected  
 object) but I'm at somewhat of a loss to understand what I'm doing  
 wrong.

There's something just like this for NSPopUpButton.  You bind its  
'content' (and possibly 'contentObjects') binding to an indexed  
collection property of the controller.  Then you bind its  
'selectedObject' binding to a to-one property of the controller.  When  
the pop-up is first set up, it displays the selected object as  
originally set on the controller's to-one property.  Then, as the user  
selects items from the pop-up, the newly selected object is passed to  
the setter for that to-one property.

Strangely, there's nothing quite like that for NSArrayController.

I think the best you can do is to bind the array controller's  
selectionIndexes binding to an attribute of your coordinating  
controller.  (For illustration purposes, I'll call this attribute  
property selectedWidgetIndexes.)  Then that coordinating controller  
can have a selectedWidget to-one property which is set up to reflect  
the object which is selected in the array controller.

One way is to make the selectedWidget property computed-on-the-fly  
based on the selection indexes:

+(NSSet*)keyPathsForValuesAffectingSelectedWidget
{
   return [NSSet setWithObject:@selectedWidgetIndexes];
}

-(Widget*)selectedWidget
{
   if (![self.selectedWidgetIndexes count])
   return nil;
   return [self.widgets objectAtIndex:[self.selectedWidgetIndexes  
firstIndex]];
}

In this scenario, you don't actually have an ivar backing the  
selectedWidget property.  It's completely based off of the  
selectedWidgetIndexes property and the widgets to-many property.   
(The widgets property is assumed to be the indexed collection property  
that the array controller is representing.  The selectedWidgetIndexes  
property can be a typical @synthesized copy property.)

Another approach is to implement the setter for selectedWidgetIndexes  
and use that to update the selectedWidget property directly.  In this  
case, selectedWidget isn't computed on the fly, but is actually held  
(cached) in an ivar:

-(void)setSelectedWidgetIndexes(NSIndexSet*)newSelectedWidgetIndexes
{
   if (![selectedWidgetIndexes isEqual:newSelectedWidgetIndexes])
   {
   [selectedWidgetIndexes release];
   selectedWidgetIndexes = [newSelectedWidgetIndexes copy];
   if ([selectedWidgetIndexes count])
   self.selectedWidget = [self.widgets objectAtIndex: 
[selectedWidgetIndexes firstIndex]];
   else
   self.selectedWidget = nil;
   }
}

You don't need +keyPathsForValuesAffectingSelectedWidget since you're  
going through the setter for the selectedWidget property.  The  
selectedWidget property can be a typical @synthesized retain property.

By the way, notice that all of this discussion is in terms of the  
array controller and the coordinating controller.  No mention of the  
table view because it's not directly relevant.  The MVC design pattern  
in action.  ;)

Regards,
Ken



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Binding to currently selected object in a list?

2009-10-09 Thread A B
Is there a way to bind an ivar to the currently selected object of a list which 
is being represented in an NSTableView via bindings?  Unfortunately there does 
not seem to be a selectedObject key (though there is one for 
selectedObjects).  Binding to the controller's selection doesn't really 
work as I'd expect and even if it did, I'd only be getting back a proxy object 
- which negates the purpose for which I want to use it, which is to call 
methods on the object.  I had put in a hack which observes changes in 
selection, gets the selectedObjects list, checks for a count  0, grabs the 
first and stuffs it into the ivar, etc. but not only does that feel really 
hackish, but doesn't always work. 

This would seem to be a pretty simple thing to want to do (i.e. present a list 
of objects, do things to/with the currently selected object) but I'm at 
somewhat of a loss to understand what I'm doing wrong.   
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com