1

これがそれほど難しいとは思いませんでしたが、プロパティの動的なクラス (現在 c# で expando オブジェクトとして設定されている) をビューに渡そうとしています。このビューでは、いくつかの jQuery テンプレートを使用してかなりの部分がレンダリングされています。これを c# コードで使用すると、次のようになります。

public dynamic SomeProperty {get;set;}
...
SomeProperty = new ExpandoObject();
SomeProperty.SomeValue = "5";
return View(TheClassThatContainsSomeProperty);

jqueryテンプレートで私ができるように:

${SomeProperty.SomeValue}

...そしてうまくいけばうまくいくでしょう。そうではありません...応答を調べると、基本的に辞書として送信されることがわかります。

SomeProperty: [{SomeValue, Value:5}]
0: {Key:SomeValue, Value:5}

これは (私が推測する) 私の次の質問につながります: jquery テンプレートで辞書にアクセスする簡単な方法はありますか? 私はこれを試しました:

${SomeProperty["SomeValue"]}

どちらも役に立たない。この時点で私が知っている唯一のことは、テンプレートに関数を配置する機能を活用することです ( jquery Web サイトからここにコピーされています)。

テンプレート:

<tr><td>${getLanguages(Languages, " - ")}</td></tr>

コード:

function getLanguages( data, separator ) {
    return data.join( separator );
}

それで、私はこれを複雑にしすぎていますか?1) jquery テンプレートから動的な値にアクセスするか、2) jquery テンプレートで辞書から値を簡単に検索できますか?

4

4 に答える 4

1

ExpandoObjectから派生し、ほとんどのシリアライザーは、を割り当てると、この型としてIEnumerable<KeyValuePair<string, Object>>a を認識します。これが、名前付きのKey :: Valueペアを使用して JavaScript 側に配列型が表示される理由です。dynamicExpandoObject

ExpandoObject クラス (System.Dynamic) @ MSDN

使用に代わる 1 つの方法ExpandoObjectは、C# の匿名型を使用することです。json にシリアル化すると、期待どおりにフィールドごとにマップされます。

匿名型 (C# プログラミング ガイド) @ MSDN

jQuery から宣言された値にアクセスすることは可能ですが、サーバー側のビュー テンプレート エンジン (カミソリなど) が既に同じことを実行できるため、jQuery で消費されるモデルをdynamic含む MVC を返すことはほとんどありません。View()オーバーヘッドの少ないテンプレート アクティビティ。代わりに、jQuery テンプレートは Ajax 呼び出しでより適切に使用されます。

dynamicサーバーで宣言された変数がブラウザーの jQuery テンプレートで使用される3 つのケースを示すコード例を次に示します。

最初の例では、メンバー フィールドに匿名型を使用し、SomeValueそれをメンバー オブジェクトとして扱う jQuery テンプレートを使用しています。

2 番目の例では、メンバー フィールドに匿名型の配列を使用し、構文を使用して項目を列挙するSomeValueテンプレートを使用しています。厳密に型指定されたサポートが得られず、正しい型を知っているか、アクセス時にそれを発見する必要があるため{{each}}、これは でうまくいかないシナリオであることに注意してください。dynamic

3 番目の例ExpandoObjectでは、メンバー フィールドSomeValueに を使用し、最初の例と同様に jQuery テンプレートを使用します (単一のメンバー オブジェクト)。この場合、ヘルパー関数を使用してKey :: Valueペアをオブジェクト メンバーpivotDictionaryMap()にピボットする必要があることに注意してください。

空白の C# MVC3 Web プロジェクトから始めて、これらの例を示すために 3 つのファイルを変更する必要があります。

_Layout.cshtml内で、jQuery テンプレート用のスクリプト インクルードと、適切なバージョンの jQuery を <head> 要素に追加します。

<script src="@Url.Content("~/Scripts/jquery-1.8.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.tmpl.js")" type="text/javascript"></script>

HomeController.cs内に、 json を返すいくつかのメソッドを追加しますActionResultSomeModelTypeまた、簡潔にするために、ここではクラスを宣言します。適切なアプリケーションでは、おそらくこのクラスがModelsで宣言されていることに注意してください。

using System.Dynamic; // up top...

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Message = "Welcome to ASP.NET MVC!";

        return View();
    }

    public ActionResult SomeDataSource(int id)
    {
        dynamic d = new { innerId = 99, innerLabel = "inside object" };
        SomeModelType obj = new SomeModelType(id, "new object");
        obj.SomeValue = d;

        return Json(obj, "text/plain");
    }

    public ActionResult SomeDataSourceWithArray(int id)
    {
        dynamic d1 = new { innerId = 99, innerLabel = "inside object (first array member)" };
        dynamic d2 = new { innerId = 100, innerLabel = "inside object (second array member)" };

        SomeModelType obj = new SomeModelType(id, "new object");
        obj.SomeValue = new object[] {d1, d2};

        return Json(obj, "text/plain");
    }

    public ActionResult SomeDataSourceWithExpando(int id)
    {
        dynamic d = new ExpandoObject();
        d.innerId = 99;
        d.innerLabel = "inside object";

        SomeModelType obj = new SomeModelType(id, "new object");
        obj.SomeValue = d;

        return Json(obj, "text/plain");
    }
}

public class SomeModelType
{
    public SomeModelType(int initId, string initLabel)
    {
        Id = initId;
        Label = initLabel;
    }

    public int Id { get; set; }
    public string Label { get; set; }
    public dynamic SomeValue { get; set; }
}

最後に、デフォルト ビューで、テンプレートのスクリプト タグとそれらを使用するために必要な JavaScript を追加します。MVCの aはデフォルトで GET リクエストを許可しないため、 $.post()and notの使用に注意してください(これらは属性でオンにできます)。$.get()JsonResult

@{
    ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>

<script id="someDataTemplate" type="text/x-jquery-tmpl">
Item <b>${Id}</b> is labeled "<i>${Label}</i>" and has an inner item with id <b>${SomeValue.innerId}</b> whose label is "<i>${SomeValue.innerLabel}</i>".
</script>

<h3>SomeDataSource Example #1 (Single Item)</h3>
<div id="someData">
</div>

<script id="someDataArrayTemplate" type="text/x-jquery-tmpl">
Item <b>${Id}</b> is labeled "<i>${Label}</i>" and has these inner items:
<ul>
 {{each SomeValue}}
    <li><b>${innerId}</b> has a label "<i>${innerLabel}</i>".</li>
 {{/each}}
</ul>
</script>

<h3>SomeDataSource Example #2 (Array)</h3>
<div id="someArrayData">
</div>

<script id="someDataTemplateFromExpandoObject" type="text/x-jquery-tmpl">
Item <b>${Id}</b> is labeled "<i>${Label}</i>" and has an inner item with id <b>${SomeValue.innerId}</b> whose label is "<i>${SomeValue.innerLabel}</i>".
</script>

<h3>SomeDataSource Example #3 (Single Item, Expando Object)</h3>
<div id="someDataFromExpandoObject">
</div>

<script type="text/javascript">
function pivotDictionaryMap(src)
{
    var retval = {};

    $.each(src, function(index, item){
        retval[item.Key] = item.Value;
    });

    return retval;
}
</script>

<script type="text/javascript">
$(document).ready(function() {
    // Ajax Round-Trip to fill example #1
    $.post("/Home/SomeDataSource/5", function(data) {
        $("#someDataTemplate").tmpl(data).appendTo("#someData");
    }, "json");

    // Ajax Round-Trip to fill example #2
    $.post("/Home/SomeDataSourceWithArray/67", function(data) {
        $("#someDataArrayTemplate").tmpl(data).appendTo("#someArrayData");
    }, "json");

    // Ajax Round-Trip to fill example #3
    $.post("/Home/SomeDataSourceWithExpando/33", function(data) {
        data.SomeValue = pivotDictionaryMap(data.SomeValue);
        $("#someDataTemplateFromExpandoObject").tmpl(data).appendTo("#someDataFromExpandoObject");
    }, "json");
});
</script>
于 2012-11-20T22:25:07.447 に答える
0

これが役立つかどうかはわかりませんが、この要点を見てください。コードスニペットから見分けるのは難しいですが、それをJSONに変換する場合は、要点で行ったようExpandoObjectに、最初にラップしてみてください。DynamicJsonObject


リンクをクリックしたくない人のためにコピー/貼り付けされた要点からのコード:

// By default, Json.Encode will turn an ExpandoObject into an array of items,
// because internally an ExpandoObject extends IEnumerable<KeyValuePair<string, object>>.
// You can turn it into a non-list JSON string by first wrapping it in a DynamicJsonObject.
[TestMethod]
public void JsonEncodeAnExpandoObjectByWrappingItInADynamicJsonObject()
{
    dynamic expando = new ExpandoObject();
    expando.Value = 10;
    expando.Product = "Apples";

    var expandoResult = System.Web.Helpers.Json.Encode(expando);
    var dictionaryResult = System.Web.Helpers.Json.Encode(new DynamicJsonObject(expando));

    Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", expandoResult); // FAILS (encodes as an array instead)
    Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult); // PASSES
}
于 2012-11-20T23:08:03.453 に答える
0

この答えが気に入らないという前提で、自分の答えを「正しい」とマークしません。誰かが私が上でやろうとしていることを理解したら、喜んでポイントをあげます.

    function getDisplayValue(data, toMatchOn) {
        var _return = $.grep(data, function (n, i) { return (n.Key == toMatchOn); })[0];

        if (_return != null)
            return _return.Value;

        return "";
    }

そしてjqueryテンプレートで:

${getDisplayValue(DisplayFields, 'Something')}

したがって、これを上記の方法で機能させることができたので、これは可能な解決策ですが、これがどの程度のパフォーマンスの低下を引き起こす可能性があるかを知るのに十分なほどjavascriptを知りません(そして、私が調査したように、この回答を更新します)しかし、JavaScript辞書はキー値に対して最適化されていると思ったので、MVCがexpandoを真のJavaScript辞書としてシリアル化しないという事実は、この回答を非常に非効率的にしているようです. そして、動的な c# オブジェクトでこのタックを最初に採用したという事実は、当初、これがよりクリーンな形式にシリアル化されると考えていたということです。とにかく、これは機能しますが、Occam's Razor はこの感覚を複雑にしすぎています。

于 2012-11-20T22:24:00.813 に答える
0

キーを見つけるために配列を反復処理している場合、パフォーマンスが大ざっぱになることは間違いありません。ただし、キーと値のペアの配列 (サーバーが送り返す) を「真の」Javascript ディクショナリ/マップに快適に変換できるはずです。例えば:

var kvps = [ {key: "test", value: "expando"}, {key: "hello", value: "world" } ]; 
var map = {};
kvps.forEach(function(kvp) { map[kvp.key] = kvp.value; } );
console.log( JSON.stringify(map) );

{"test":"expando","hello":"world"}

もちろん、ネストされたオブジェクトの場合は、上記のアプローチに再帰を適用して機能させる必要があります。

于 2012-11-21T18:07:56.273 に答える