7

簡単に言うと、質問です。

MVCでは、チェックボックスのクリック(または選択ボックスまたはリストボックスの変更)と人間の意味での「コントローラー、モデルの変更」と、チェックボックスのクリック(または選択ボックスまたはリストボックスの変更)とコントローラーの意味での「私」をどのように区別しますかmモデルが変更されたため、ビューを更新しますか?」


例:

「Edges」で接続された「Vertices」の概念を持つJSアプリ(すべて1つの大きなHTML + JSページ。背後にサーバーがあり、AJAXが実行されていますが、例では重要ではありません)があります。UIを使用すると、マップ上の頂点を追加および削除したり、頂点のペア間のエッジを有効または無効にしたりできます。

頂点Aから頂点Bへのエッジを無効にする方法は2つあります。

  1. エッジをクリックして、[エッジの詳細]ウィンドウに[このエッジを無効にする]ボタンを表示します。また
  2. 頂点A(またはB)をクリックして、[頂点の詳細]ウィンドウに近くの頂点のチェックリストを表示し、そこから頂点B(またはA)のチェックを外すことができます。

これがMVCの内部でどのように機能するかを示します(ただし、私の理解の問題を修正する更新については、この投稿の最後を参照してください):

  • モデル:頂点オブジェクトのリストとエッジオブジェクトのリスト。
  • ビュー:マーカーとポリラインに加えて、チェックボックスとボタン、および「頂点の詳細」と「エッジの詳細」のDIVを備えたGMapsUI。
  • コントローラ:
    • チェックボックスとボタンのイベントが発生したときにモデルを更新するJS関数。と
    • モデルのイベントが発生したときにビューを更新するJS関数。

これが特定の優雅さです:

  1. ユーザーは、頂点Aに焦点を合わせた頂点詳細ウィンドウと頂点Aから頂点Bへのエッジに焦点を合わせたエッジ詳細ウィンドウを持っています。
  2. ユーザーは、[エッジの詳細]ウィンドウで[このエッジを無効にする]をクリックします。
  3. コントローラ関数1はクリックイベントを取得し、Edgeモデルオブジェクトでdisable()を呼び出します。
  4. Edgeモデルオブジェクトは、「Ijustgetdisabled」イベントを発生させます。
  5. コントローラ機能2は、「無効になりました」イベントを受け取り、
    1. エッジ詳細ウィンドウを再描画して、「無効になっています!」と表示します。と
    2. [頂点の詳細]ウィンドウで[頂点B]のチェックを外します。
      1. くだらない!これにより、エッジが無効になったことを意味するUIイベントをリッスンしていたコントローラー関数1が再度起動されます。

そのため、モデルの不要な再更新とビューの再更新があります。イベントを発生させるイベントを発生させるイベントを含むより複雑なビューでは、これにより、数十の無関係な更新が行われる可能性があります。


更新:素晴らしい答え。

私はMVCを少し誤解しました。上で説明したように、ビューは1つだけではありません。複数のモデルに複数のビューがあります。特に、特定のノードに対するチェックボックスリストのエッジのビューと、別の「詳細なウィンドウスタイル」のエッジのビューがあります。

さらに、モデルが変更されたときにすべてのビューを更新する1つのコントローラー関数を使用するべきではありません。モデルが変更されたときに、各ビューはそれ自体を変更する必要があります。

したがって、各ビューがモデルの「状態更新」イベントに登録され、各ビューがそれらのイベントの受信時にそれ自体を更新する場合、私の循環イベントの質問に対する答えは単純に次のようになります。

チェックボックスリストビューは、モデルの状態が変更された後にチェックボックスを更新している間、チェックボックスイベントを無効にします。

これで、ユーザーが[エッジの詳細]ウィンドウでエッジを無効にすると、コントローラーがエッジモデルを更新し、チェックボックスリストビューが更新の通知を受け取り、チェックボックスリストビューがスマートで、チェックボックスイベントを消音してステータスを変更します。適切なチェックボックス。

これは、1つのコントローラーがすべてのビューを更新する元のソリューションよりもはるかに口当たりが良く、ループを回避するために特別な注意とフィードが必要なビューを知る必要があります。代わりに、厄介なUI要素を持つ単一のビューだけが問題に対処する必要があります。

私の質問に答えてくれた人たちに感謝します!

4

2 に答える 2

3

MVCモデルを要約するだけです。通常、ビューは自分自身を更新する必要があります。コントローラーがモデルの状態を変更し、モデルがそのビューに更新を送信し、ビューがモデルから新しい状態を取得して自分自身を更新します。コントローラーとビューは一般的にバンドルされていますが (つまり、グラフィック表現でデータをドリルダウンします)、モデルを介してのみ直接対話することはありません。これはもちろん一般的に。

したがって、ビューを更新する JS 関数は実際にはコントローラーではありません。これは重要な違いです。それらはビューの一部と見なされるべきです。これは当面の問題には役立たないかもしれませんが、指摘する価値があると思いました.

モデルを削除することもできません。モデルによってサポートされていない場合、ビューやコントローラーは実際には存在できない (または機能状態にある) ため、モデルから何かを削除していることを意味していると思います。

JS コード ジョッキーではなく、gmap を使用したことがないため、どこに問題があるのか​​ わかりません。チェックボックス(checkedプロパティ)の状態を変更すると、onClick()イベントが発生しますか? それは本当に私見ではありませんが、おそらく彼らはそのように実装しました。それ以外の場合は、コントローラーを onClick() にアタッチし、チェックボックスにロジックを追加して (または、これは JS で、どこかの関数で) チェックボックスの状態を変更することができます。 . それが不可能な場合は、オプション 1 と 2 が間違いなく最善の策です。

追加: ビューと対話するユーザー

では、ユーザーがビューを操作したい場合はどうなるでしょうか? 多くの場合、ウィジェットにはビューとコントローラーの両方が含まれます。チェックボックスには、ビュー (チェックされているかどうかを確認できます) とコントローラー (クリックできます) があります。チェックボックスをクリックすると、原則として次のようになります。

  • チェックボックスコントローラーがイベントを受け取る
  • チェックボックス コントローラは、このチェックボックスがモデルで表す値の状態を変更します
  • モデルはリスナーを更新します (チェックボックスを含む)
  • チェックボックスの外観を更新して、その値が変更されたことを反映します

最初のステップ、コントローラーがイベントを受け取る方法は言語に依存しますが、OOP 言語では、この特定のウィジェットのユーザー インターフェイス イベントにアタッチされたリスナー オブジェクトである可能性が高く、コントローラーであるか、ユーザー インタラクションをコントローラーに通知します。

于 2008-12-18T09:25:04.600 に答える
0

これは難しいものです。私が正しく理解していれば、モデルにクリックハンドラーを公開し、モデルのクリックイベントがコントローラーによってキャッチされたために問題が発生します。コントローラはビ​​ューを更新し、ビューは同じイベントを切り替えます。

私の観点からは、コントローラーがEdgeのClickイベントに自分自身をアタッチすることは不適切であると考えます。これは、Edgeの実装方法と使用方法に関する詳細が公開されすぎるためです。コントローラは、Edgeの使用方法やその他の実装の詳細を気にしません。

実際、正規のMVCスタイルでは、コントローラーがモデルイベントにフックする必要はまったくありません。これは通常、モデルの状態がビューや他のコントローラーによって変更されないためです。モデルが変更されたことをコントローラーに通知する必要はありません。

問題を解決するには、ToggleEdgeなどの単一のメソッドを持つようにViewのインターフェースを定義する必要があります。


public interface GraphView
{
    event Action ToggleEdge;
}

EdgeClickedとCheckboxClickedの2つのメソッドを作成したいのですが、そのような2つの独立したメソッドを主張することは、カプセル化の原則に違反します。それはあなたのコントローラーまたはそれらのイベントにフックしたい他の誰かにあまりにも多くの実装の詳細を公開します。コントローラは、ビューの状態が変更されたことだけを気にし、どのように変化したかは気にしないことを忘れないでください。

ユーザーインターフェイスにViewインターフェイスを実装するときは、ToggleEdgeイベントが1つの場所から呼び出されるように注意する必要があります。これを行うには、ビューのEdge.Clickedイベントにフックし、それを使用してチェックボックスを切り替えます。これにより、チェックボックスがトグルベントをコントローラーまで上げる役割を果たします。


public class UI : UserControl, GraphView
{
    public event Action ToggleEdge;

    void OnToggleEdge(Edge edge)
    {
        if (ToggleEdge != null)
            ToggleEdge(edge);
    }

    protected void Edge_Clicked(object sender, EventArgs e)
    {
        CheckBox chkbox = FindCheckBoxThatCorrespondsToEdge((Edge)sender);
        chkbox.Checked = !chkbox.Checked;    
    }

    protected void chkEdge_CheckChanged(object sender, EventArgs e)
    {
        Edge edge = FindEdgeThatCorrespondsToCheckbox((CheckBox)sender);
        OnToggleEdge(edge);
    }
}

ビューがその実装についてあまりにも多くを知っているという議論をすることができます:エッジとチェックボックスが基本的に接続されていることを認識しています。これは別のハックかもしれませんが、「UIロジック」がビューの表示を同期し続ける必要があるため、おそらく却下される可能性があります。

于 2008-12-17T18:53:55.047 に答える