2014-05-07 50 views
0

所以我有一個接口,像這樣:ASP.NET MVC:創建使用接口作爲模型的動態視圖

public interface ISettings 
    { 
     string Name { get; } 
    } 

和各種實現方式,例如:

public class SettingsA : ISettings 
{ 
    public string Name { get { return "Example A"; } } 

    public string CustomAttributeA1 { get; set; } 

    public string CustomAttributeA2 { get; set; } 
} 

public class SettingsB : ISettings 
{ 
    public string Name { get { return "Example B"; } } 

    public string CustomAttributeB1 { get; set; } 

    public string CustomAttributeB2 { get; set; } 
} 

現在我有問題需要創建一個動態的UI(通過ISettings作爲模型,並根據每個實現的屬性生成控件)。所以我有這樣的:

Edit.cshtml:

@model ISettings 

@Html.EditorForModel(Model) 

這是很好的產生所需要的字段,但這個問題是我不能輕易地定製它(例如:添加CSS類引導或不管我想要什麼其他CSS)..我想我可以使用基於HTML標籤的CSS選擇器..但似乎不是理想的方法。這個問題有沒有一些很好的解決方法?處理這種情況的最佳方法是什麼?

+0

一個解決方案一個粗略的想法將是寫一個基於反射的,CSS類生成器。 –

+0

查看MVC中的HTML自定義編輯器。你可以寫出自己的html擴展名並獲得你想要的結果。例如:@ Html.MattEditorForModel(Model)。這是非常簡單和乾淨的方式。 http://www.c-sharpcorner.com/UploadFile/ashish_2008/htmlhelper-methods-in-Asp-Net-mvc1/ –

回答

0

我找到了解決辦法早就忘了回到這裏後......我不能發表一切,我做到了,但其基本思想是將屬性添加到ISettings接口,如:

public interface ISettings 
{ 
    string Name { get; } 

    string EditorTemplatePath { get; } 
} 

然後你需要在每個類中重寫這個。例如:

public class SettingsA : ISettings 
{ 
    public string Name { get { return "Example A"; } } 

    public string EditorTemplatePath 
    { 
     get{ return "~/Views/Shared/EditorTemplates/SettingsA.cshtml"; } 
    } 

    public string CustomAttributeA1 { get; set; } 

    public string CustomAttributeA2 { get; set; } 
} 

public class SettingsB : ISettings 
{ 
    public string Name { get { return "Example B"; } } 

    public string EditorTemplatePath 
    { 
     get{ return "~/Views/Shared/EditorTemplates/SettingsB.cshtml"; } 
    } 

    public string CustomAttributeB1 { get; set; } 

    public string CustomAttributeB2 { get; set; } 
} 

當然,您需要在控制器的某處實現自己的邏輯來返回自定義HTML。對於我來說,我使用AJAX和做這樣的事情:

[Route("get-editor-ui/{type}")] 
public ActionResult GetEditorUI(string type) 
{ 
    var model = // logic to get the model from "type" argument 

    if (model == null) 
    { 
     return HttpNotFound(); 
    } 

    string content = RenderRazorPartialViewToString(model.EditorTemplatePath, model); 
    return Json(new { Content = content }, JsonRequestBehavior.AllowGet); 
} 

僅供參考,RenderRazorPartialViewToString是我的基本控制器和定義如下:

public string RenderRazorPartialViewToString(string viewName, object model) 
{ 
    ViewData.Model = model; 
    using (var sw = new StringWriter()) 
    { 
     var viewResult = System.Web.Mvc.ViewEngines.Engines.FindPartialView(ControllerContext, viewName); 
     var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw); 
     viewResult.View.Render(viewContext, sw); 
     viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View); 
     return sw.GetStringBuilder().ToString(); 
    } 
} 
0

嘗試用一些HTML助手,如:

public static class MyHtmlExtensions 
{ 
    public static string GetCssForMyDiv(this HtmlHelper htmlHelper) 
    { 
     if (htmlHelper.ViewData.Model is SettingsA) return "class-a"; 
     else if (htmlHelper.ViewData.Model is SettingsB) return "class-b"; 
     else return ""; 
    } 
} 

從來沒有這樣做之前應該做工相當精細。

你會碰到這樣的:

<div class="class-base my-class my-div-style @Html.GetCssForMyDiv()"> 
    Check my CSS classes! 
</div> 

你可以用一下IDisposable接口,並有一些很酷的東西是:

@using(var div = Html.BeginDivWithCustomCssClassPerType()) 
{ 
    <span>Check my CSS classes!</span> 
} 

這些擴展實際上可能幫助你與你的EditorFor。您可能會保留EditorFor調用,該調用將爲ISettings呈現EditTemplate,並且您將在此處放置擴展方法以在不同的繼承情況下提供不同的行爲。

另一種方法是簡單地爲每個具體類型(繼承)設置不同的EditTemplate元素,如果它們彼此差別很大,請使用特定模板名稱調用EditorFor

+0

感謝您的回覆,但事情是我不知道什麼類型將提前。它們來自插件,因此無法事先知道這些屬性會是什麼。我認爲唯一的解決方法可能需要在我的界面中添加一些GetHtml()方法..所以每個實現都可以提供一個獨特的UI。 – Matt

+0

您的核心模塊無法猜測插件方法 - 這就是您提供定義良好的插件合同的原因。你猜'GetHtml()'是正確的。用類似的東西來定義契約,並在某個'try-catch'內調用該方法,因爲誰知道插件dev是否在任何地方放置了'throw NotImplementedException()'...... –

+0

只是爲了補充:方法契約是不是*唯一*的方式去。例如,你可以定義一個屬性,並在我建議的擴展類上使用反射來獲取特定類型的自定義屬性,如'[OutputCssClass('my-css-class')]'或其他。這取決於你,雖然方法調用比反射快得多以查找屬性。 –