Objective c 在自定义控件上正确实现自定义绑定
由于所有这些日历样式Objective c 在自定义控件上正确实现自定义绑定,objective-c,macos,cocoa-bindings,foundation,Objective C,Macos,Cocoa Bindings,Foundation,由于所有这些日历样式NSDatePickers占用了大量空间,我决定将它们放在视图控制器中,使用按钮显示日期本身,然后单击使用nspover在弹出窗口中显示日历 然后,我使用绑定将NSButton子类的date属性与NSArrayController当前选择的NSDate类型属性链接起来。然后传播到日历样式的日期选择器中,反之亦然。对于“另一种方式”,我没有使用KVO,而是简单地实现自定义设置器,因此如果有人在按钮或日历视图控制器上设置date的值(可能是绑定到数组控制器设置了按钮的值,因此按钮
NSDatePicker
s占用了大量空间,我决定将它们放在视图控制器中,使用按钮显示日期本身,然后单击使用nspover
在弹出窗口中显示日历
然后,我使用绑定将NSButton
子类的date
属性与NSArrayController
当前选择的NSDate
类型属性链接起来。然后传播到日历样式的日期选择器中,反之亦然。对于“另一种方式”,我没有使用KVO,而是简单地实现自定义设置器,因此如果有人在按钮或日历视图控制器上设置date
的值(可能是绑定到数组控制器设置了按钮的值,因此按钮设置了日历视图控制器的值;可能是日历上的更改设置了视图控制器的值;谁知道呢)——然后我传播更改
最后一切都很顺利…除了一件事
多重选择
您可以看到,在用户执行多个选择后,系统立即正确地决定告诉我的按钮选择现在是nil
。为了传播更改,我告诉所有绑定的观察者该值已更改为nil
。其中一个绑定的观察者是NSArrayController
,它当前是选择了多个项目
问题是什么?将当前选择的绑定键路径设置为nil
会导致将选择中的所有日期设置为nil
…将更改传播到数据库中。而且用户甚至没有将值设置为nil
-这是简单地进行多个选择,而不是进行任何选择的结果它应该只用于显示这个值
谢天谢地,现在我不需要为这些日历支持多个选择。我只需通过使用isEqual:
比较观察对象的观察关键路径值来检测NSMultipleSelectMarker
)。如果进行了多次选择,我会将该值应用于ivar,但不会“双向”通知其他绑定对象该更改
但是--如果我想支持用户选择几个文档,然后立即更改它们的所有发布日期(用户可以使用在标准NSDatePicker
,NSTextField
等中完成的绑定实现)--如果不创建多个选择并向所有选定对象传播错误更改(如设置nil
),我将如何执行此操作
(注意:虽然这个问题是为了反映我当前重用标准控件(按钮、弹出框、日期选择器)的需要而写的,但它并不限于这种重用。明天我可能想实现一个完全自定义的函数图小部件,它需要双向Cocoa绑定。)
下面是一些有关IRDatePopoverEditorButton的代码块:
+ (void)initialize
{
[super initialize];
[self exposeBinding:@"date"];
[self exposeBinding:@"minDate"];
[self exposeBinding:@"maxDate"];
}
- (void)awakeFromNib
{
[super awakeFromNib];
// …
[self establishBindings];
}
- (void)establishBindings
{
NSArray *keys = [NSArray arrayWithObjects:@"date", @"minDate", @"maxDate", nil];
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSContinuouslyUpdatesValueBindingOption,
[NSNumber numberWithBool:YES], NSConditionallySetsEnabledBindingOption,
[NSNumber numberWithBool:YES], NSValidatesImmediatelyBindingOption,
[NSNumber numberWithBool:NO], NSRaisesForNotApplicableKeysBindingOption,
[NSNumber numberWithBool:NO], NSAllowsEditingMultipleValuesSelectionBindingOption,
nil];
// This code allows creation of bindings via interface builder without actual
// support for custom bindings in IB. I hijack the 'user defined runtime attributes'
// and define binding keypath there, and I use an IBOutlet to define a binding
// target.
for(NSString *key in keys)
{
id bindingTarget = [self valueForKey:[key stringByAppendingString:@"BindingTarget"]];;
id bindingKeyPath = [self valueForKey:[key stringByAppendingString:@"BindingKeyPath"]];;
if (!bindingTarget || !bindingKeyPath)
continue;
[bindingTarget valueForKeyPath:bindingKeyPath];
[self bind:key
toObject:[self valueForKey:[key stringByAppendingString:@"BindingTarget"]]
withKeyPath:[self valueForKey:[key stringByAppendingString:@"BindingKeyPath"]]
options:options];
}
}
// one of the custom setters
- (void)setDate:(NSDate *)date
{
if(_date == date)
return;
[self willChangeValueForKey:@"date"];
[date retain];
[_date release];
_date = date;
[self didChangeValueForKey:@"date"];
NSDictionary * infoForBinding = [self infoForBinding:@"date"];
if(infoForBinding && [infoForBinding objectForKey:NSObservedObjectKey])
{
id observedObject = [infoForBinding objectForKey:NSObservedObjectKey];
NSString * observedKeyPath = [infoForBinding objectForKey:NSObservedKeyPathKey];
if([[observedObject valueForKeyPath:observedKeyPath] isEqual:NSMultipleValuesMarker])
{
// This is needed because, when performing multiple selection,
// we get called with setDate:nil. Then we blindly apply this to
// the entire selection.
// For our needs, it's enough to block applying values to multiple
// selection. But it's not a correct solution.
// FIXME: we currently block editing of multiple selection.
NSLog(@"Not applying value for keypath %@ to %@; currently multiple items are selected", observedKeyPath, observedObject);
}
else
{
[observedObject setValue:date forKeyPath:observedKeyPath];
}
}
if(self.date)
if(self.formatter)
[self setTitle:[self.formatter stringForObjectValue:date]];
else
[self setTitle:[date description]];
else
[self setTitle:@"-"];
}