6

データをフィルタリングするために使用する多くのプロパティを持つ Filter プロパティを持つ ViewModel があります。

例:

class MyViewModel : IHasFilter
{
     public MyData[] Data { get; set; }
     public FilterViewModel Filter { get; set; }
}

class FilterViewModel
{
    public String MessageFilter { get; set; }
    //etc.
}

私のビューを使用する場合、これは正常に機能します。のプロパティを設定できModel.Filter、それらは Controller に渡されます。私が今やろうとしているActionLinkのは、上記の形式で機能するクエリ文字列を持つ を作成することです。

上記のビューによって生成されたクエリ文字列は次のようになります。

http://localhost:51050/?Filter.MessageFilter=Stuff&Filter.OtherProp=MoreStuff

上記のビューに移動するグリッドの行ごとに、異なるビューで ActionLink を生成する必要があります。

私が試してみました:

Html.ActionLink(
    item.Message,
    "Index",
    "Home",
    new { Filter = new { MessageFilter = item.Message, }, },
    null);

routeValuesまた、引数を次のように設定しようとしました:

new MyViewModel { Filter = new FilterViewModel { MessageFilter = item.Message, }, },

ただし、これらは上記のようなクエリ文字列を生成しません。

4

2 に答える 2

2

興味深い質問 (+1)。目的は、デフォルトのモデル バインダーを使用してクエリ文字列パラメーターをパラメーターにバインドすることであると想定していActionます。

箱から出してすぐに、ActionLinkメソッドがこれを行うとは思いません(もちろん、独自のロールを作成することを妨げるものは何もありません)。リフレクターを見ると、objectが に追加されるとRouteValueDictionary、キーと値のペアのみが追加されることがわかります。これはキーと値のペアを追加するコードであり、ご覧のとおり、オブジェクト プロパティをトラバースしていません。

foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
{
    object obj2 = descriptor.GetValue(values);
    this.Add(descriptor.Name, obj2);
}

だからあなたのオブジェクトのために

var values = new { Filter = new Filter { MessageFilter = item.Message } }

追加されるキーはFilterで、値はFilterオブジェクト タイプの完全修飾名に評価されるオブジェクトです。

この結果は ですFilter=Youre.Namespace.Filter

正確なニーズに応じて可能なソリューションを編集します


拡張メソッド は機能します

静的フレームワーク メソッドExpressionHelperModelMetadata(既存のヘルパーでも使用されます) を使用して、既定のモデル バインダーが理解する適切な名前とプロパティの値をそれぞれ決定することに注意してください。

public static class ExtentionMethods
{
    public static MvcHtmlString ActionLink<TModel, TProperty>(
        this HtmlHelper<TModel> helper,
        string linkText,
        string actionName,
        string controllerName,
        params Expression<Func<TModel, TProperty>>[] expressions)
    {
        var urlHelper = new UrlHelper(helper.ViewContext.HttpContext.Request.RequestContext);

        var url = urlHelper.Action(actionName, controllerName);

        if (expressions.Any())
        {
            url += "?";

            foreach (var expression in expressions)
            {
                var result = ExpressionHelper.GetExpressionText(expression);

                var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, helper.ViewData);

                url = string.Concat(url, result, "=", metadata.SimpleDisplayText, "&");
            }

            url = url.TrimEnd('&');
        }

        return new MvcHtmlString(string.Format("<a href='{0}'>{1}</a>", url, linkText));
    }
}

サンプルモデル

public class MyViewModel
{
    public string SomeProperty { get; set; }

    public FilterViewModel Filter { get; set; }
}

public class FilterViewModel
{
    public string MessageFilter { get; set; }
}

アクション

public ActionResult YourAction(MyViewModel model)
{
    return this.View(
        new MyViewModel
        {
            SomeProperty = "property value",
            Filter = new FilterViewModel
            {
                MessageFilter = "stuff"
            }
        });
}

使用法

paramsメソッドの最後のパラメーターを使用して、任意の数のビュー モデル プロパティをクエリ文字列に追加できます。

@this.Html.ActionLink(
    "Your Link Text",
    "YourAction",
    "YourController",
    x => x.SomeProperty,
    x => x.Filter.MessageFilter)

マークアップ

<a href='/YourAction/YourController?SomeProperty=some property value&Filter.MessageFilter=stuff'>Your Link Text</a>

string.Formatを使用する代わりにTagBuilder、URL で安全に渡されるようにクエリ文字列をエンコードする必要があります。この拡張メソッドには追加の検証が必要ですが、役立つと思います。また、この拡張メソッドは MVC 4 用に作成されていますが、以前のバージョン用に簡単に変更できることにも注意してください。MVC タグの 1 つがバージョン 3 用であることに今まで気づきませんでした。

于 2012-04-04T12:39:23.673 に答える
1

インスタンスから1つのRouteValueDictionaryを作成しFilterViewModel、それを使用ToDictionaryして、すべてのキーの前に。が付いた別のRouteValuesに渡すことができます'Filter.'

RouteValueDictionaryさらに、プレフィックスを受け入れる特別なオーバーライドを作成できます(したがって、他のシナリオでより便利になります)。

public class PrefixedRouteValueDictionary : RouteValueDictionary
{
  public PrefixedRouteValueDictionary(string prefix, object o)
    : this(prefix, new RouteValueDictionary(o))
  { }

  public PrefixedRouteValueDictionary(string prefix, IDictionary<string, object> d)
    : base(d.ToDictionary(kvp=>(prefix ?? "") + kvp.Key, kvp => kvp.Value))
  { }
}

これで、次のことができるようになります。

Html.ActionLink( 
  item.Message, 
  "Index", 
  "Home", 
  new PrefixedRouteValueDictionary("Filter.", 
    new FilterViewModel() { MessageFilter = item.Message }), 
  null); 

ただし、これに対する注意点は、、、AddおよびメソッドがRemoveを考慮に入れるように変更されていないことです。これは、これらのメソッドのバージョンを定義することで実現できますが、仮想ではないため、ではなく、話していることを知っている呼び出し元からのみ機能します。TryGetValuethis[string key]prefixnewPrefixedRouteValueDictionaryRouteValueDictionary

于 2012-04-04T12:58:48.483 に答える