Re: MultiBinding
Re: MultiBinding
On 28 Oct 2013, at 20:35, email@hidden wrote:
> On 28 Oct 2013, at 17:52, Gerd Knops <email@hidden> 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 (email@hidden)
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:
This email sent to email@hidden