在VIew上的mvc3中有多个IEnumerable工具

时间:2014-06-25 09:10:41

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4 mvcgrid

@{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No").Filterable(true);
})

但我想做那样的事情:

@if(some conditon)
{
@{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
}
else
{
@{IEnumerable<BC.Models.RIGHTS> data = ViewBag.list;} 
}
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

但它没有用,任何人都可以对此有所了解 现在 如果我做这样的事情就行了

@if(some conditon)
    {
    @{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
    @Html.Grid(data).Columns(columns =>
    {
    columns.Add(c => c.APPLICATION_NO).Titled("Application No");
    })
    }
    else
    {
    @{IEnumerable<BC.Models.RIGHTS> data = ViewBag.list;} 
    @Html.Grid(data).Columns(columns =>
    {
    columns.Add(c => c.APPLICATION_NO).Titled("Application No");
    })
    }

我的问题是两个Model类中都存在APPLICATION_NO属性,因此我不想使用

    @Html.Grid(data).Columns(columns =>
    {
    columns.Add(c => c.APPLICATION_NO).Titled("Application No");
    })

我的代码中有两次。

3 个答案:

答案 0 :(得分:5)

你的问题是你没有使用MVC中最重要的概念:视图模型。

至于您的上一条评论,您要使用的是视图模型,即专门为将视频发送到视图以显示它而创建的类。

这样做:

  1. 创建一个公共类,其中包含APPLICATION_NO(视图模型类所需)
  2. 创建另一个公共类,它将成为您的视图模型。这是一个在剃刀模板上根据需要对数据进行整形的类(在这种情况下,它将保存1中定义的类的列表)
  3. 在控制器中
  4. ,返回传递模型的视图作为第二个参数。即不要使用ViewBag / ViewData,而应使用视图模型,例如return View("ViewName", model)
  5. 在视图中使用模型:使用@model声明模型类型,并使用提供的Model变量在Razor模板中使用它
  6. 通过这种方式,您可以在服务器上整形数据,并避免在Razor模板中包含大量代码(这是不可取的)。当然,你有智能感知,你的模板也会被输入。

    代码1:

    public class ApplicationModel
    {
       public int APPLICATION_NO {get; set;}
    }
    

    代码2:

    public class ApplicationsViewModel
    {
       public List<ApplicationModel> Applications { get; set; }
    }
    

    3代码(控制器内部)

    var model = new ApplicationsViewModel();
    
    if (...) // include the condition to choose the kind of data inside the list
    {
       model.Applications = list.Select(item =>
         new ApplicationModel { APPLICATION_NO = item.APPLICATION_NO } ).ToList()
    }
    else
    {
       // same code here, for the other kind of data in the list
    }
    
    // return the view with this model
    return View("ApplicationView", model);
    

    代码4:

    // decalre the model type at the beginning
    @model YourNamespace.ApplicationViewModel;
    
    // access the model using the Model variable
    @Html.Grid(Model.Applications).Columns(columns =>
      {
      columns.Add(c => c.APPLICATION_NO).Titled("Application No");
      })
    

    这使您可以构建具有多个优势的MVC应用程序,例如可测试性,代码重用,可读性或ModelState的可用性。相信我,许多事情真的非常非常重要,特别是ModelState

    此外,您可以在视图模型中使用代码注释(为HTML帮助程序提供额外信息的属性),这些属性可以提供标签,验证和其他一些自动功能。

    不要怀疑在视图模型中包含所有需要的属性。

    使用视图模型可以创建ad-hoc类,而无需更改域或业务层类,即您不需要使用接口,代码注释等。然而,很多时候在业务类中添加代码注释并将它们嵌套在视图模型中是很有趣的。

    请记住,有时您可以使用相同的视图模型将数据发布回服务器,并将其指定为POST操作的参数类型。

    顺便说一下,接口解决方案很好,但是这个解决方案不需要接口。 (这个解决方案使用该界面会有更好的实现,但这是你的选择)。

答案 1 :(得分:3)

@if(some conditon)
{
@{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
}
else
{
@{IEnumerable<BC.Models.RIGHTS> data = ViewBag.list;} 
}
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

代码无法正常工作,因为数据是在块中声明的。 如果网格只能在两个类的共享字段上工作,您可以考虑使用APPLICATION和RIGHTS将实现的接口并更改代码,如下所示:

@{IEnumerable<BC.Models.IAPPLICATION_NO> data = (IEnumerable<BC.Models.IAPPLICATION_NO>)ViewBag.list;} 
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

其中IAPPLICATION_NO是如下界面:

public interface IAPPLICATION_NO
{
    string APPLICATION_NO { get; }
}

我不知道APPLICATION_NO是什么,所以我使用了字符串,界面只能为网格定义。

否则,如果需要为这两种类型显示不同的数据,则应考虑在if块中使用两个视图或不同的网格声明。

我在VS上做了一个关于答案的样本:

我附上了代码:

public interface AInterface
{
    string AProperty { get; }
}

public class AList : AInterface
{
    public string AProperty { get; set; }
}

public class BList : AInterface
{
    public string AProperty { get; set; }
}

这些是

现在是控制器:

public class TestController : Controller
{
    public ActionResult Index()
    {
        var random = new Random((int)DateTime.Now.Ticks);

        if (random.Next() % 2 == 0)
            ViewBag.List = new List<AList> { new AList { AProperty = "Atestvalue" } };
        else
            ViewBag.List = new List<BList> { new BList { AProperty = "Atestvalue" } };

        return View();
    }
}

和视图:

@{
    ViewBag.Title = "Index";
    IEnumerable<TestMvcApplication.Interfaces.AInterface> test = ViewBag.List;
}

<h2>Index</h2>

@foreach (var item in test)
{
    <div>
        @item.AProperty
    </div>
}

这可以解决你的问题,你可以看到

不使用接口:

@{IEnumerable<dynamic> data = (IEnumerable<dynamic>)ViewBag.list;} 
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

但是你失去了IntelliSense完成功能,如果成员丢失,我认为你会收到运行时错误。

我尝试过你的Grid程序集,但它使用了c#Expression,它与动态不兼容。 另一个解决方案是使用控制器中的LINQ将一个列表转换为另一个列表:

IEnumerable<BC.Models.Application> data;
if (some condition)
{
    data = applicationList; //applicationList's type is IEnumerable<BC.Models.Application>
}
else
{
    data = rightsList.Select(t => new Application { APPLICATION_NO = t.APPLICATION_NO }); //rightsList's type is IEnumerable<BC.Models.RIGHTS>
}

ViewBag.list = data;

在视图中,您可以将发布的工作代码保留在问题的顶部。你没有multitype IEnumerable支持,因为你只使用一种类型,但没有在这些类之间使用公共接口我认为我们必须去反思,但我认为编写该代码很难。

答案 2 :(得分:0)

为什么不

@{string columnName = "default column name";
if(some_condition)
{
    // I'm not sure what's going on with the data variable
    columnName = "alternate column name";
}
else
{
    // Again, do your stuff with the data variable
}
}
@Html.Grid(data).Columns(columns =>
{
    columns.Add(c => c.APPLICATION_NO).Titled(columnName);
})

如果你试图在你的观点中过于聪明,我认为你最终会得到(充其量)令人困惑的代码。除非IEnumerable<A>IEnumerable<B>以及网格呈现A:ISomeInterface,否则用于呈现B:ISomeInterface的网格无法呈现ISomeInterface。或者,只需将列名称作为视图模型的属性传递。