2013-10-01 42 views
2

比如我有這三類:在視圖中顯示更多從抽象基礎派生的類型的最佳方式是什麼?

public abstract class AbstractBase 
{ 
    public int A { set; get; } 
} 

public class Derived1 : AbstractBase 
{ 
    public int B { set; get; } 
    public int C { set; get; } 
} 

public class Derived2 : AbstractBase 
{ 
    public int D { set; get; } 
} 

而且,隨着AbstractBase

public class AbstractBaseService 
{ 
    public IEnumerable<AbstractBase> GetInstances() 
    { 
     var results = new List<AbstractBase>(); 

     // TODO: Get data 

     return results; 
    } 
} 

列表返回一個服務,我想在一個強類型ASP.NET MVC視圖來顯示這些類在表中(或WF中的GridView)。那麼最好的方法是什麼?而如果我想添加編輯選項呢?

enter image description here

+0

在這個特殊的例子中,你可能會要求你的蛋糕並且吃它。抽象基礎只能將A展現給你的視圖。如果你需要*'B','C'或'D',那麼你就不得不用你當前的設計來貶低:'if(result Derived1){// downcast}'。否則,我會從類層次結構中重新考慮您的設計。 –

+0

但我的域模型需要這種結構。我想避免檢查視圖什麼是動態類型 – jannagy02

+0

然後,如果您的域模型服務也只能生成'AbstractBase',那麼您就會陷入向下轉向。另一個「竅門」是通過將響應與一個枚舉進行分組,以指示您實際正在使用哪個類,來移除*類型檢查。同樣,這將要求您至少能夠控制您的服務。 –

回答

2

您可以在場景中使用顯示模板

這個想法是爲每個具體的派生類型創建一個顯示模板,並讓MVC在運行時找出列表中每個項目的具體類型,然後拿起適當的模板。

假設我們有以下的控制器的操作方法,它返回一個視圖顯示AbstractBase對象的列表:

public ActionResult Foo() 
{ 
    var list = new List<AbstractBase>() 
    { 
     new Derived1{ A = 1, B = 2, C = 3}, 
     new Derived2{ A = 1, D = 4}, 
    }; 
    return View(list); 
} 

您可以創建以下模板:

〜/查看/共享/DisplayTemplates/Derived1.cshtml

@model MvcApplication1.Models.Derived1 
<td> 
    @Html.DisplayFor(m => m.A) 
</td> 
<td> 
    @Html.DisplayFor(m => m.B) 
</td> 
<td> 
    @Html.DisplayFor(m => m.C) 
</td> 
<td></td> 

〜/查看/共享/顯示模板/ Derived2.cshtml

@model MvcApplication1.Models.Derived2 
<td> 
    @Html.DisplayFor(m => m.A) 
</td> 
<td></td> 
<td></td> 
<td> 
    @Html.DisplayFor(m => m.D) 
</td> 

不幸的是,你要顯示在表格中的項目,你將需要爲不相關的每個具體類型列提供空TR元素。

和主視圖〜/瀏覽/首頁/ Foo.cshtml將看起來像:

@model IEnumerable<MvcApplication1.Models.AbstractBase>   
<table> 
    <thead> 
     <tr> 
      <th>Col A</th> 
      <th>Col B</th> 
      <th>Col C</th> 
      <th>Col D</th> 
     </tr> 
    </thead>  
    <tbody> 
     @foreach(var item in Model) 
     { 
      <tr> 
       @Html.DisplayFor(m => item) 
      </tr> 
     } 
    </tbody> 
</table> 

這需要AbstractBase對象的列表,並在列表上建立表迭代的身體,爲每個項目調用DisplayFor。 MVC將在運行時檢查每個項目的具體類型,然後在DisplayTemplates文件夾中搜索適當的視圖。

這是最簡單的方法,其中公共基類中的字段由每個具體派生類模板呈現。 但是,爲基類中的字段設置通用模板是有意義的。

您可以創建在基類中的字段,〜/瀏覽次數另一個顯示模板/共享/ DisplayTemplates/AbstractBase.cshtml

@model MvcApplication1.Models.AbstractBase 
<td> 
    @Html.DisplayFor(m => m.A) 
</td> 

這怎麼模板領域的公共基類將是如果你使用的是MVC 4,那麼這個函數會依賴於它。 如果您使用的是MVC 4,則可以從派生類的每個模板調用基本模板。例如,對於Derived1的模板將是這樣的:

@model MvcApplication1.Models.Derived1 
@Html.DisplayFor(m => m, "AbstractBase") 
<td> 
    @Html.DisplayFor(m => m.B) 
</td> 
<td> 
    @Html.DisplayFor(m => m.C) 
</td> 
<td></td> 

如果你不是在MVC 4,可悲的是嵌套顯示編輯器不工作,所以行@Html.DisplayFor(m => m, "AbstractBase")上面什麼都不會做。

您在MVC4之外的第一個也是最好的選擇是手動將基類的模板作爲局部視圖呈現。這條線將被@Html.Partial("~/Views/Shared/DisplayTemplates/AbstractBase.cshtml", Model)

另一種選擇是我會建議你避免是在調用抽象類模板移動到主視圖,而不是從每個派生類模板被稱爲替代。 如果基類的模板需要嵌入到每個派生類生成的某個元素中,這可能甚至不是一個有效的選項。例如,它不會是一個選項,如果基類中的列並沒有全部在每一行的開頭(或結尾)

這樣呈現視圖主視圖會做:

@foreach(var item in Model) 
{ 
    <tr> 
     @Html.DisplayFor(m => item, "AbstractBase") 
     @Html.DisplayFor(m => item) 
    </tr> 
} 

我總是堅持從每個衍生模板調用基本模板,如果您發現自己使用最後一種方法,我會說你應該非常小心。否則,您每次需要渲染派生模板時都需要記住調用@Html.DisplayFor(m => item, "AbstractBase"),並且使用該方法可能無法實現某些html設計。

希望它能幫助!

相關問題