2

セットアップは次のとおりです。プロパティがsharedzoomValueのキーにバインドされているIKImageBrowserView のサブクラスがあります。バインディングが同じキーにバインドされている があります。VFBrowserZoomValueNSUserDefaultsControllerNSSlidervalue

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 が IKImageBrowserView の Zoom Value バインディングを参照するために を使用する必要があるのは少し残念です@"zoomValue"。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

これが予想される動作だと思います。バインディングドキュメントのこのFAQセクションを参照してください。手動でプッシュする必要があります。

于 2010-01-25T15:43:18.547 に答える
0

バインディング互換のコントロールを作成する場合 (または、この場合はサブクラス化する場合)、値が変更されたときにコントローラーに通知するのはコントロール次第です。したがって、やりたいことはオーバーライドです

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

observableController興味のあるバインディングに注意してください。 and を追跡します(値変換が使用される場合keyPathは辞書も同様です)。optionsコントロールの値を更新するときは、送信する必要があります

[observableController setValue:newValue forKeyPath:keyPath];

新しい値でコントローラーを更新します。キー値の監視は一方通行であり、バインディングではコントロールはオブザーバーです。

于 2010-01-25T16:06:26.453 に答える