2

这是设置:我有一个 IKImageBrowserView 的子类,它的zoomValue属性绑定到VFBrowserZoomValueshared 中的一个键NSUserDefaultsController。我有一个NSSlidervalue绑定绑定到同一个键。

zoomValue这可以完美地从滑块更改浏览器。

我正在尝试-magnifyWithEvent:在我的IKImageBrowserView子类中实现以允许在触控板上使用捏合手势缩放浏览器。

这是我的实现:

-(void)magnifyWithEvent:(NSEvent *)event
{
  if ([event magnification] > 0) {
    if ([self zoomValue] < 1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
  } 
  else if ([event magnification] < 0) {
    if ([self zoomValue] + [event magnification] > 0.1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
    else {
      [self setZoomValue: 0.1];
    }
  }
}

这会zoomValue正确更改浏览器。问题是NSUserDefaults没有用新值更新。

在应用程序的其他地方,我有一个-observeValueForKeyPath:ofObject:change:context:观察浏览器的zoomValue. 如果我在该方法中记录浏览器的缩放值、滑块的值和默认值,我会看到浏览器的 zoomValue 没有被推入 NSUserDefaults 并且滑块没有更新。

我试过-magnifyWithEvent:用调用来包围该方法,-{will,did}ChangeValueForKey但没有效果。

4

3 回答 3

4

绑定的 KVO 流程不是正交的;绑定不是属性,它是对属性的引用。这是绑定如何工作的简写:

  • KVO 用于将更改从模型传递到控制器和视图。
  • KVC 用于将更改从视图传递到控制器和模型。

因此,当具有绑定的视图处理事件时,它需要将更改传播到其绑定引用自身的属性。

以下是您的代码可能的样子,它使用一种实用方法来完成通过绑定传播更改的繁重工作:

- (void)magnifyWithEvent:(NSEvent *)event
{
  if ([event magnification] > 0) {
    if ([self zoomValue] < 1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
  } 
  else if ([event magnification] < 0) {
    if ([self zoomValue] + [event magnification] > 0.1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
    else {
      [self setZoomValue: 0.1];
    }
  }

  // Update whatever is bound to our zoom value.
  [self updateValue:[NSNumber numberWithFloat:[self zoomValue]]
         forBinding:@"zoomValue"];
}

不幸的是,ImageKit 需要使用@"zoomValue"来引用 IKImageBrowserView 的 Zoom Value 绑定,AppKit 中的大多数绑定都有自己的全局字符串常量,例如NSContentBinding.

这是通过绑定传播更改的通用实用程序方法:

- (void)updateValue:(id)value forBinding:(NSString *)binding
{
  NSDictionary *bindingInfo = [self infoForBinding:binding];

  if (bindingInfo) {
    NSObject *object = [bindingInfo objectForKey:NSObservedObjectKey];
    NSString *keyPath = [bindingInfo objectForKey:NSObservedKeyPathKey];
    NSDictionary *options = [bindingInfo objectForKey:NSOptionsKey];

    // Use options to apply value transformer, placeholder, etc. to value
    id transformedValue = value; // exercise for the reader

    // Tell the model or controller object the new value
    [object setValue:transformedValue forKeyPath:keyPath];
  }
}

实际应用占位符、值转换器等作为练习留给读者。

于 2010-01-25T22:13:00.047 回答
0

恐怕这是预期的行为,请参阅绑定文档的此常见问题解答部分。您需要手动推送。

于 2010-01-25T15:43:18.547 回答
0

当您创建与绑定兼容的控件(或者,在您的情况下,子类化一个)时,由控件在其值更改时通知控制器。所以,你想要做的是覆盖

- (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options

并留意您感兴趣的绑定。跟踪observableControllerkeyPath(以及options字典,如果将使用任何值转换器)。当您更新控件的值时,您需要发送

[observableController setValue:newValue forKeyPath:keyPath];

用新值更新控制器。键值观察是一条单行道,在绑定中,控件是观察者。

于 2010-01-25T16:06:26.453 回答