On 28 Oct 2013, at 20:35, jonat...@mugginsoft.com wrote:

> On 28 Oct 2013, at 17:52, Gerd Knops <gerti-cocoa...@bitart.com> wrote:
> 
>> In Interface Builder text fields you can use "Value with Pattern" to combine 
>> multiple properties into a single output. Alternatively in code you can do 
>> something like this:
>> 
>> Gerd
>> 
> 
> Thanks Gerd
> 
> Value with Pattern works as advertised for NSTextField.
> Unfortunately I am binding to an NSPopupButton which lacks this binding.
> 
> XAML bindings, though similar in nature to Cocoa bindings, are somewhat more 
> flexible I think.
> The following illustrates more or less what I need to emulate.
> 
> The converter (eqv to the value transformer) operates on self.name and 
> PeriodTypeComboBox.SelectedItem.Name
> 
> <ComboBox.ItemTemplate>
>       <DataTemplate>
>               <TextBlock>
>                       <Run>Based on a</Run>
>                       <Run>
>                               <Run.Text>
>                                       <MultiBinding 
> Converter="{StaticResource StringReplaceConverter}" 
> ConverterParameter="Period">
>                                               <Binding Path="Name" />
>                                               <Binding 
> ElementName="PeriodTypeComboBox" Path="SelectedItem.Name" />
>                                       </MultiBinding>
>                               </Run.Text>
>                       </Run>
>               </TextBlock>
>       </DataTemplate>
> </ComboBox.ItemTemplate>
> 
My solution to providing some sort of emulation of the above behaviour is:

1. Define a NSObject category property bindingDelegate implemented as an 
associated object. All objects that want to make use of delegate based binding 
must have this defined.
    eg: [myArray makeObjectsPerformSelector:@selector(setBindingDelegate:) 
withObject:self]
    myArray supplies content to myArrayController.

2. Use a custom binding key path, bind=. To bind to -name via the delegate the 
binding key path is bind=name. 
   I could have used bind@name but I thought it would start to get confused 
with the existing usage of @ in bindings.

3. Define a category based override of - (id)valueForUndefinedKey:
    The override looks for the delegate prefix and if found calls the delegate 
method - (id)boundObject:(id)boundObject valueForUndefinedKey:(NSString *)key 
options:(NSDictionary *)options;
    The delegate can construct the binding value with arbitrary complexity.

Usage is simple:

1. Set the bindingDelegates on myArray (objects of type MyBoundData) as shown 
above.
2. Set the NSPopupButton ContentValues binding to 
myArrayController.arrangedObjects.bind=name
3. Implement the binding delegate method:

- (id)boundObject:(id)boundObject valueForUndefinedKey:(NSString *)key 
options:(NSDictionary *)options
{
    id value = nil;
    Class boundClass = [boundObject class];
    
    if (boundClass == [MyBoundData class]) {
    
        // bound with bind=name
        if ([key isEqualToString:@"name"]) {
            NSString *stringValue = [NSString stringWithFormat:@"Based on a 
%@", [boundObject valueForKey:key]];        // transform the value
            NSString *periodType = 
self.periodTypePopupButton.titleOfSelectedItem;      // Modify based on another 
control
            value = [stringValue 
stringByReplacingOccurrencesOfString:@"Periodly" withString:periodType];
        }
    }

Note that the bind=name syntax could be extend to bind{key:value}=name to allow 
for passing additional options to the binding delegate.

Jonathan

/*==============================
NSObject+BindingSupportDelegate.h
==============================*/

@protocol BPBindingSupportDelegate <NSObject>
@required

/*!
 
 Delegate returns a computed value for the bound object key path.
 
 */
- (id)boundObject:(id)boundObject valueForUndefinedKey:(NSString *)key 
options:(NSDictionary *)options;
@end


@interface NSObject (BindingSupportDelegate)

- (id)extValueForKey:(NSString *)key withTransformerForName:(NSString 
*)transformerName;

/*!
 
 A delegate object dedicated to provide binding support
 
 */
@property (nonatomic, retain) id <BPBindingSupportDelegate> bindingDelegate;

@end

/*==============================
NSObject+BindingSupportDelegate.m
==============================*/

// The minimal form acceptable form. A  more general form could be 
bind{key:value,...}=
NSString *BindingSupportDelegatePrefix = @"bind=";

@implementation NSObject (BrightPay)

#pragma mark -
#pragma mark Binding delegate

- (void)setBindingDelegate:(id)object
{
    objc_setAssociatedObject(self, @selector(bindingDelegate), object, 
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)bindingDelegate {
    return objc_getAssociatedObject(self, @selector(bindingDelegate));
}

#pragma mark -
#pragma mark KVC key handling

- (id)valueForUndefinedKey:(NSString *)key
{
    id value = nil;
    
    // Look for delegate binding prefix
    NSRange prefixRange = [key rangeOfString:BindingSupportDelegatePrefix];
    if (prefixRange.location == 0 && [key length] > prefixRange.length && 
self.bindingDelegate) {
        
        NSString *targetKey = [key substringFromIndex:prefixRange.length];
        value = [self.bindingDelegate boundObject:self 
valueForUndefinedKey:targetKey options:nil];
    }
    
    // Reproduce default implementation behaviour
    if (!value) {
        [NSException exceptionWithName:NSUndefinedKeyException
                                reason:@"Key not found"
                              userInfo:@{ @"NSTargetObjectUserInfoKey": self , 
@"NSUnknownUserInfoKey": key}
         ];
    }
    
    return value;
}
@end



_______________________________________________

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

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

Reply via email to