1

我有一个购物篮,其中包含用户选择的项目并存储在会话变量中。我希望在每个视图上显示关于篮子状态的各种值,即篮子:1,但我只能看到如何将其传递给单个入口点的视图。我将如何使用此列表初始化每个视图?

4

2 回答 2

0

child action你可以在你的布局中渲染一个。子动作的想法是它可以与主动作并行执行一些逻辑。

例如,您可以拥有以下控制器:

public class ShoppingBasketInfoController: Controller
{
    [ChildActionOnly]
    public ActionResult Index()
    {
        var model = Session["info"] as ShoppingInfoViewModel;
        return PartialView(model);
    }
}

然后你就会有一个对应的局部视图(~/Views/ShoppingBasketInfo/Index.cshtml):

@model ShoppingInfoViewModel
<div>
    You have @Html.DisplayFor(x => x.NbProducts) in your basket
</div>

然后你可以在你的布局中找到一个合适的地方来呈现这个动作:

@Html.Action("Index", "ShoppingBasketInfo")

现在,您的所有视图都将在指定位置显示此信息,而无需担心此信息来自何处、如何存储或使用什么视图模型。主要动作完全独立。

我用[ChildActionOnly]属性修饰了子操作,以确保永远不会通过来自客户端的正常 HTTP 请求访问此操作,例如/ShoppingBasketInfo/Index. 它只能在主要执行动作的上下文中使用。

于 2013-01-17T13:50:15.527 回答
0

您最好的选择可能是基本控制器、基本视图模型、接口和动作过滤器的组合。

// Interface.  To be implemented by model and controller.
public interface IHoldABasket 
{
    Basket Basket { get; set; };
}

// Base view model.  Has a basket as public property.
public BaseBasketViewModel : IHoldABasket 
{
      public Basket Basket { get; set; }
}

// Base controller model.  Also has a basket.
public BaseController : Controller, IHoldABasket 
{
   public Basket Basket { get; set; }

   public BaseController() 
   {
       AttemptBasketLoad();
   }

   private void AttemptBasketLoad()
   {
       // Replace the SomeMethodToLoadBasket with whatever method you use
       // to retrieve a basket.
       Basket = SomeMethodToLoadBasket();
   }
}

// Action Filter
public class BasketAwareAttribute : ActionFilterAttribute 
{
   public override void OnActionExecuted(ActionExecutedContext filterContext)
   {
        // If controller can hold basket AND model can hold basket
        if (filterContext.Controller is IHoldABasket 
            && filterContext.Controller.ViewData.Model is IHoldABasket)
        {
            // Copy basket from controller into model.
            // Will now be accessible through Basket property on model.
            ((IHoldABasket)filterContext.Controller.ViewData.Model)
               .LoggedInUser
                = ((IHoldABasket)filterContext.Controller).LoggedInUser;

        }

        base.OnActionExecuted(filterContext);
   }
}

这就是排序的基础设施。让我们看一个实际的例子。您可能有一个 ProductListViewModel。那应该从基本视图模型类继承。

首先,确保您的 ProductListViewModel 继承自 BaseBasketViewModel。

public class ProductListViewModel : BaseBasketViewModel 
{
}

由于继承,您的视图模型包含一个篮子对象并实现 IHoldABasket 接口。

您的控制器将从 BaseController 继承。

public class ProductController : BaseController 
{

}

控制器方法如下所示。

[BasketAware]
public ViewResult Products(int page = 1) 
{
   // Load VM that implements IHoldABasket
   // Really contrived, I know... :P

   var vm = new ProductListViewModel() { Results = productServices.Search() };

   return View(vm);
}

应该是这样的。幕后发生的事情是

  • 基本控制器尝试加载一个篮子,如果找到一个则将其存储
  • Controller 和 Model 继承了一个通用接口,使得从控制器到模型的自动复制更容易实现。
  • 动作过滤器在最后一分钟加载。如果控制器和模型都可以容纳一个篮子(例如两个工具IHoldABasket),则篮子从控制器复制到模型。
  • 从 BaseBasketViewModel 派生的所有视图模型都将具有一个名为 Basket 的公共属性。
于 2013-01-17T14:01:17.543 回答