3

タイプのいくつかの Wicket 入力フィールドについて何かを検証する必要がありますTextField<BigDecimal>(つまり、パーセンテージの合計が 100 であること)。このような入力フィールドは 1 つから多数あります。つまり、事前に何人かわかりません。

(簡略化した例)

private class PercentageValidator extends AbstractFormValidator {
    @Override
    public FormComponent<?>[] getDependentFormComponents() {
        // ...
    }

    @Override
    public void validate(Form<?> form) {
        List<TextField<BigDecimal>> fields = // TODO

        // the actual validation where the value of every field is needed
    }
}

ListView の Java コード:

ListView<?> listView = new ListView<PropertyShare>("shares", shares) {
    @Override
    protected void populateItem(ListItem<PropertyShare> item) {
    // ... 
        item.add(new TextField<BigDecimal>("share", ... model ...));
    }
};

HTML:

<tr wicket:id="shares">
   <td> ... </td>
   <td>
     <input wicket:id="share" type="text" size="4"> %
   </td>

</tr>

すべての TextField を Page のコレクションに保持しようとしましたが、このアプローチは失敗します。これは、Page が最初に作成されるだけでなくpopulateItem()、囲みのメソッドListViewが呼び出されるため、重複するフィールドがコレクションに追加されるためです。(重複しないようにする簡単な方法がわかりませんでした。)

validate()ListView が使用されているという事実も、メソッド内のフォーム オブジェクトからフィールドを見つけるのをやや複雑にしているようです。ListView を取得してform.get("shares")、その子を反復処理する必要があると思いますか?

のようなリピーターで囲まれた任意の数のフィールドにアクセスする「正しい方法」は何ListViewですか?

4

3 に答える 3

5

別のアプローチは、サブクラス化してからTextField、 a を使用してサブクラスVisitorのすべての子孫コンポーネントを選択することです。

このようにして、チェックされていないキャストを回避でき、ID に依存する必要がなくなります。これは、あまり堅牢なアプローチではありません。

編集:実際には、次のようになります。

サブクラス:

private static class ShareField extends TextField<BigDecimal> {
   // ...
}

フォームからすべての ShareFields を見つけるヘルパー メソッド:

private List<ShareField> findShareFields(Form form) {
    final List<ShareField> fields = Lists.newArrayList();
    form.visitChildren(ShareField.class, new IVisitor<ShareField>() {
        @Override
        public Object component(ShareField component) {
            fields.add(component);
            return CONTINUE_TRAVERSAL;
        }
    });
    return fields;
}
于 2012-05-30T20:51:02.380 に答える
2

私が見る限り、リスト ビューでアイテムの再利用プロパティを設定していません。Javaドキュメントから:

true の場合、ウィンドウがまったく変更されない場合、またはウィンドウがスクロールされる場合 (ページングと比較して)、リスト ビューの再レンダリングがより効率的になります。ただし、listView モデル オブジェクトを変更する場合は、ListItems を再構築するために手動で listView.removeAll() を呼び出す必要があります。フォームに ListView をネストする場合は、常にこのプロパティを true に設定してください。そうしないと、検証が正しく機能しません。

ただし、リストビューの子をVisitorで反復処理することもできます。Wicket は、ビューに追加したコンポーネントを常に追跡します。

于 2012-05-30T16:59:41.337 に答える
2

そうです、質問を書いているときに、の子を単純にループして、form.get("shares")ID「共有」でフィールドを取得するだけでうまくいくことに気づきました。

確かにそうです。「共有」フィールドを見つけるヘルパー メソッドを次に示します。

@SuppressWarnings("unchecked")
private List<TextField<BigDecimal>> findFields(Form form) {
    List<TextField<BigDecimal>> fields = Lists.newArrayList();
    MarkupContainer container = (MarkupContainer) form.get("shares");
    for (Iterator<? extends Component> it = container.iterator(); it.hasNext();) {
        MarkupContainer c = (MarkupContainer) it.next();
        fields.add((TextField<BigDecimal>) c.get("share"));
    }
    return fields;
}

ただし、上記のメソッドにはやや醜いキャストが 3 つあり、そのうちの 1 つ ( Component-> TextField<BigDecimal>) は「チェックされていないキャスト」の警告を生成します。

このソリューションをクリーンアップできる場合、またはより良いアプローチを知っている場合は、お気軽にコメントするか、他の回答を投稿してください!

于 2012-05-30T15:40:50.693 に答える