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