19

私が達成したいことは、かなり単純であるように思えます。ここにサンプル プロジェクトを配置しました。

NSDictionaries の配列で満たされた NSArrayController があります。

[[self controller] addObject:@{ @"name" : @"itemA", @"part" : @"partA" }];
[[self controller] addObject:@{ @"name" : @"itemB", @"part" : @"partB" }];
[[self controller] addObject:@{ @"name" : @"itemC", @"part" : @"partC" }];

「name」キーに基づいて、この配列の項目を NSPopupButton に入力しています。これは、次のバインディングで簡単に実現できます

バインディング

次に、NSPopupButton の現在の選択に基づいて、「part」キーのテキストを NSTextField に入力したいと思います。次のバインディングをセットアップしました。

テキストフィールドバインディング

これらのバインディングだけでは、テキスト フィールドに「partC」が表示されます。

初期表示

しかし、NSPopupMenu の値を変更しても、テキスト フィールドに表示される内容は変わりません。

これは単に NSPopupButton で「選択したオブジェクト」バインディングを設定するだけの問題だと思いました

選択したオブジェクト

しかし、それは機能していません。奇妙な理由でメニューにプロキシオブジェクトが表示されます(ボーナスになる理由を提供します)。

ウィンドウ2

では、これを機能させるにはどうすればよいでしょうか。

4

1 に答える 1

58

この場合、「選択したオブジェクト」を使用しないでください。ポップアップの「選択されたインデックス」バインディングを NSArrayController のselectionIndexコントローラー キーにバインドします。サンプル プロジェクトで試してみたところ、うまくいきました。

編集:

selectionIndexoverを使用するのが適切な理由を尋ねましたselectedObject。最初の背景:

ポップアップ メニューをバインドする場合、バインドできる仮想の「コレクション」が 3 つあります。Contentは抽象的な「メニューにあるもののリスト」です。常にContentを指定する必要があります。Content ObjectsContent Valuesも指定しない場合、Contentにバインドされた値のコレクションが「オブジェクト」として使用され、それらのメソッドによって返される文字列-descriptionが「値」として使用されます。つまり、コンテンツ値はポップアップに表示される文字列であり、コンテンツ オブジェクトはそれらが対応するものです (文字列ではない可能性があり、-descriptionポップアップでテキストを生成するのに適したメソッド)。ここで重要なのは、ここで 3 つの異なる「仮想配列」が潜在的に作用していることです: Contentの配列、コンテンツ オブジェクトの配列 (異なる場合があります)、およびコンテンツ値の配列(これも異なる場合があります)。これらはすべて同じ数の値を持ち、通常、コンテンツ オブジェクトコンテンツ値は、コンテンツ配列内の対応する項目の関数 (数学的な意味で) になります。

次に理解すべき重要なことはNSArrayController、 の人生における目的の一部は、ユーザーの選択を追跡することです。これは、ポップアップの場合はわずかに (まったく) 興味深いだけですが、NSTableView. 内部的には、任意の時点で選択されるContent配列内のインデックスをNSArrayController保持することで、これを追跡します。そこから、便宜上、選択状態がいくつかの異なる方法で公開されます。NSIndexSet

  • selectionIndexes説明どおりです - Content配列NSIndexSetで選択されたアイテムのインデックスを含む
  • selectionIndex複数選択をサポートしていないアプリケーションに便利なオプションです。と同等と考えることができますarrayController.selectionIndexes.firstIndex
  • selectedObjectは単一選択の場合にも役立ち、概念的にはContentObjectsArray[arrayController.selectionIndexes.firstIndex]
  • selection配列コントローラーのコンテンツ配列内の基礎となるオブジェクト (または複数選択の場合はオブジェクト) への読み取りと書き込みを仲介する特別なオブジェクト (コンシューマーには不透明) を返します。複数の選択ケースで一度に複数のオブジェクトを編集できるようにし、他の特殊なケースをサポートするために存在します。(このプロパティは読み取り専用と考える必要があります。その型は消費者には不透明であるため、それに書き込む適切な新しい値を作成することはできません。: のような呼び出しを行うことは意味がありますが、次のような呼び出しを行うことは意味が-[arrayController.selection setValue: myObject forKey: @"modelKey"]ありません。-[arrayController setValue: myObject forKey: @"selection"]

プロパティを理解したところでselection、一歩下がって、この場合に使用するのが適切ではない理由を見てみましょう。 NSPopUpButton賢くしようとしています: ContentおよびContent Valuesバインディングを介して、メニューに含める必要があるもののリストを提供しました。次に、そのSelected ObjectNSArrayControllerselectionプロパティにバインドすることをさらに伝えました。あなたはおそらくこれを「書き込み専用」バインディングと考えているでしょう。つまり、「親愛なるポップアップ、ユーザーの選択を取り、それを arrayController にプッシュしてください」ですが、バインディングは実際には双方向です。そのため、バインディングが更新されると、ポップアップは最初にコンテンツ/コンテンツ値からのすべての項目をメニューに取り込みます「ああ、あなたは の値arrayController.selectionが私のSelected Object だとおっしゃいました。それは奇妙です - それは私のContent/Content Valuesバインディングにバインドされたもののリストにありません。私はそれをリストに追加したほうがいいですあなた! 私はそれを呼び出し-descriptionて、その文字列をメニューに挿入することでそれを行います." しかし、Selected Objectバインディングから得られるオブジェクトは、上記の不透明な選択オブジェクトです (結果から、それが class であることがわかります。これは_NSControllerObjectProxy、先頭のアンダースコアによって示唆されるように、AppKit へのプライベート クラスです)。

つまり、ポップアップのSelected Objectバインディングをアレイ コントローラのコントローラ キーにバインドするが間違っている理由です。残念ながら、Cocoa バインディングのドキュメントは表面をなぞり始めたに過ぎないことをお気づきだと思いますが、気を悪くしないでください。私はここ数年、大規模なプロジェクトでほぼ毎日 Cocoa バインディングを使用してきましたが、まだ完全には理解していないユースケースがたくさんあると感じています。selection

于 2013-02-18T12:41:25.843 に答える