【问题标题】:Multiple IEnumerable implement in mvc3 on VIewVIew 上的 mvc3 中的多个 IEnumerable 实现
【发布时间】:2014-08-15 18:34:14
【问题描述】:
@{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");
    })
    }

我的问题是两个模型类中都存在 APPLICATION_NO 属性,所以我不想使用

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

在我的代码中有两次。

【问题讨论】:

  • 请准确说出你想要达到的目标。
  • APPLICATION_NO 属性是否仅在 BC.Models.APPLICATION 类型上定义?
  • 在我的视图中,我有一个 MVC 网格,我只能使用其中一个 @{IEnumerable data = ViewBag.list;} 或 @{IEnumerable data = ViewBag.list;} 但我想在 if else 条件下同时使用它们@Yair
  • APPLICATION_NO 属性在应用程序模型类以及权利模型类@Haim 中定义
  • 顺便说一句,一旦您进入 if/else 块,您就不需要将代码包含在 @{} 中。我很惊讶它没有给你一个警告,如果它编译/工作的话。

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


【解决方案1】:

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

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

这样做:

  1. 创建一个具有APPLICATION_NO 的公共类(视图模型类需要)
  2. 创建另一个公共类作为您的视图模型。这是一个在 razor 模板上根据需要对数据进行整形的类(在这种情况下,它将保存 1 中定义的类的列表)
  3. 在您的控制器中,返回传递模型作为第二个参数的视图。 IE。不要使用ViewBag/ViewData,而是使用视图模型,例如return View("ViewName", model)
  4. 在您的视图中使用模型:使用@model 声明模型类型,并使用提供的Model 变量在 Razor 模板中使用它

通过这种方式,您可以在服务器上调整数据,并避免在 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 助手提供额外信息的属性)之外,这些属性还可以提供标签、验证和其他一些自动功能。

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

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

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

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

【讨论】:

  • +1 使用视图模型并强烈键入您的视图,而不是使用 ViewBags。
【解决方案2】:
@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 块中。 如果网格只能在两个类的共享字段上工作,您可以考虑使用 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是什么,所以我用的是string,接口只能定义get for grid。

否则,如果您需要为这两种类型显示不同的数据,您应该考虑在 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# 表达式并且与动态不兼容。 另一种解决方案是在控制器中使用 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;

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

【讨论】:

  • 我不想使用两个不同的网格。
  • @Amit 我没有说要使用两个不同的网格,我建议您使用这些类必须继承的接口并使用单个 IEnumerable 数据,就像您编写的第一个示例一样工作。
  • 我想在不使用任何界面的情况下做到这一点
  • 使用单个数据的最后一个选项是动态的。 IEnumerable data = ViewBag.List
  • 关于控制器如何定义动态。
【解决方案3】:

为什么不

@{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&lt;A&gt; 的网格不适用于渲染IEnumerable&lt;B&gt;,除非A:ISomeInterfaceB:ISomeInterface 并且网格渲染ISomeInterface。或者,只需将列名作为视图模型的属性传递。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    相关资源
    最近更新 更多