2012-04-04 25 views
6

Tôi có một ViewModel với một tài sản Lọc rằng có nhiều tài sản mà tôi sử dụng để lọc dữ liệu của tôiLàm thế nào để tạo ra một ActionLink với Properties cho Xem Mẫu

Ví dụ:

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

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

này hoạt động tốt khi bằng cách sử dụng chế độ xem của tôi. Tôi có thể thiết lập các thuộc tính của Model.Filter và chúng được chuyển tới Bộ điều khiển. Những gì tôi đang cố gắng làm bây giờ, là tạo ra một ActionLink có một chuỗi truy vấn hoạt động với định dạng trên.

Chuỗi truy vấn được tạo ra bởi Xem của tôi từ trên cao trông như thế này:

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

tôi cần phải tạo ra một ActionLink trong một Xem khác nhau cho mỗi hàng trong một mạng lưới mà đi vào Xem trên.

Tôi đã thử:

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

Tôi cũng đã cố gắng thiết lập các tham số routeValues tới:

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

Nhưng những không tạo ra các chuỗi truy vấn như trên.

+0

+1 câu hỏi hay –

+0

cảm ơn chỉnh sửa; Tôi refactored câu trả lời và thay thế quên thêm 'tiền tố'! –

+0

@AndrasZoltan Không có vấn đề gì. – DaveShaw

Trả lời

1

Bạn có thể tạo một RouteValueDictionary từ một trường hợp FilterViewModel và sau đó sử dụng ToDictionary vào đó để vượt qua RouteValues ​​khác với tất cả các phím bắt đầu bằng 'Filter.'.

Lấy nó hơn nữa, bạn có thể xây dựng một override đặc biệt của RouteValueDictionary mà chấp nhận một tiền tố (do đó làm cho nó hữu ích hơn cho các kịch bản khác):

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)) 
    { } 
} 

Với rằng bây giờ bạn có thể làm:

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

Tuy nhiên, hãy báo trước điều này là các phương pháp Add, Remove, TryGetValuethis[string key] không bị thay đổi để tính đến số prefix. Điều đó có thể đạt được bằng cách xác định các phiên bản new của những phương pháp đó, nhưng vì chúng không ảo, chúng chỉ hoạt động từ những người gọi biết rằng họ đang nói chuyện với một số PrefixedRouteValueDictionary thay vì RouteValueDictionary.

+0

Điều này cũng tương tự như suy nghĩ ban đầu của tôi. Một báo trước nữa là bạn chỉ có thể có một tiền tố cho mỗi cuộc gọi phương thức ActionLink và tất cả các mục sẽ phải có tiền tố. Tôi cập nhật câu trả lời của tôi với một giải pháp có thể khác tùy thuộc vào nhu cầu chính xác và nghĩ rằng bạn có thể quan tâm. Chúc mừng. – Craig

2

Câu hỏi thú vị (+1). Tôi giả định rằng mục đích là sử dụng trình kết nối mô hình mặc định để ràng buộc các tham số chuỗi truy vấn tới các tham số Action của bạn.

Hết hộp Tôi không tin rằng phương pháp ActionLink sẽ làm điều này cho bạn (tất nhiên không có gì ngăn cản bạn tự mình lăn). Nhìn vào phản xạ, chúng ta có thể thấy rằng khi object được thêm vào RouteValueDictionary, thì chỉ có cặp giá trị khóa mới được thêm vào. Đây là mã bổ sung các cặp giá trị khóa và bạn có thể thấy không có sự vượt qua các thuộc tính đối tượng.

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

Vì vậy, đối tượng của bạn

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

phím được bổ sung là Filter và giá trị là đối tượng Filter của bạn mà sẽ đánh giá vào tên đầy đủ của các loại đối tượng của bạn.

Kết quả của việc này là Filter=Youre.Namespace.Filter.

Sửagiải pháp khả thi tùy theo nhu cầu chính xác của bạn


Extension Methodlàm công việc

Lưu ý rằng nó sử dụng phương pháp khung tĩnh ExpressionHelperModelMetadata (mà cũng được sử dụng bởi những người trợ giúp hiện có) để xác định tên thích hợp mà Trình mô hình hóa mặc định sẽ hiểu và giá trị của thuộc tính tương ứng.

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)); 
    } 
} 

mẫu Models

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

    public FilterViewModel Filter { get; set; } 
} 

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

Action

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

Cách sử dụng

Bất kỳ số thuộc tính mô hình chế độ xem nào của bạn có thể được thêm vào chuỗi truy vấn thông qua thông số params cuối cùng của phương thức.

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

Markup

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

Thay vì sử dụng string.Format bạn có thể sử dụng TagBuilder, querystring nên được mã hóa để được thông qua một cách an toàn trong một URL và phương pháp mở rộng này sẽ cần một số xác nhận thêm nhưng Tôi nghĩ nó có thể hữu ích. Cũng lưu ý rằng, mặc dù phương pháp mở rộng này được xây dựng cho MVC 4, nó có thể dễ dàng sửa đổi cho các phiên bản trước. Tôi đã không nhận ra rằng một trong những thẻ MVC đã được cho phiên bản 3 cho đến bây giờ.

+0

* tất nhiên là không có gì ngăn cản bạn từ việc lăn của riêng bạn * - và làm thế nào tôi có thể làm điều đó? :) Và bạn đã đúng, tôi đã nhìn thấy "Filter = Your.Nam ...". – DaveShaw

+0

@DaveShaw mặc dù bạn có thể không đồng ý, tôi cảm thấy như đây là một câu trả lời có giá trị cho câu hỏi của bạn. cổ vũ. – Craig

+0

@DaveShaw đang nghĩ về điều này trên đường về nhà từ nơi làm việc và đã đâm vào nó. Giải pháp này có thể được trưởng thành khi bạn làm việc với nó nhưng tôi nghĩ rằng nó có thể hữu ích. – Craig

Các vấn đề liên quan