2017-05-04 125 views
0

我正在學習asp.net mvc,使用visual studio community 2017,並且作爲一種教學項目,我正在製作一個web應用程序,用於跟蹤鍛鍊情況。我的模型由WorkOut對象組成,這些對象具有練習的列表(或更具體的ICollection),並且每個練習都有一個ICollection。下面是我的模型類的基礎知識。如何構建asp.net mvc中複雜對象的創建視圖?

public class WorkOut 
    { 
     public int Id { get; set; } 
     public int Length { get; set; } 
     public DateTime Date { get; set; } 
     public virtual ICollection<Exercise> ExerciseList { get; set; } 
    } 
public class Exercise 
    { 

     public int Id { get; set; } 
     public string Name { get; set; } 
     public int WorkOutId { get; set; } 
     public virtual WorkOut WorkOut { get; set; } 
     public virtual ICollection<RepUnit> Sets { get; set; } 
    } 
public class RepUnit 
    { 
     public int Id { get; set; } 
     public int Rep { get; set; } 
     public int? Weight { get; set; } 
     public int ExerciseId { get; set; } 
     public virtual Exercise Exercise { get; set; } 
    } 

使用WorkOut自動生成視圖作爲模型導致創建操作和視圖,只生成Length和Date屬性。通常,自動生成的視圖和控制器僅添加非虛擬屬性。所以我想,也許我必須做一個多步驟的創作過程;創建鍛鍊,創建鍛鍊並添加鍛鍊,將鍛鍊添加到鍛鍊中,停止鍛鍊或添加其他鍛鍊。所以我認爲Id讓VS對我來說是一些工作,並且我爲每個模型對象類型(WorkOutsController,ExercisesController,RepUnitsController)製作控制器和視圖,稍後我會修剪出不重要的視圖,甚至重構操作i實際上使用到一個新的控制器。 所以WorkOutController我的POST動作是這樣的。

public ActionResult Create([Bind(Include = "Id,Length,Date")] WorkOut workOut) 
     { 
      if (ModelState.IsValid) 
      { 
       db.WorkOuts.Add(workOut); 
       db.SaveChanges(); 

       return RedirectToAction("Create","Exercises",new { workoutId = workOut.Id }); 
      } 
      return View(workOut); 
     } 

因此,我將workoutI運行到運動控制器,但這是我不確定如何繼續。我想繼續攜帶workoutId,並在下一步中爲練習命名,同時顯示剛剛添加的相關日期。我唯一能想到的就是像Exercise一樣在ExerciseController的GET操作中實例化一個練習。

public ActionResult Create(int workoutID) 
     { 
      Exercise ex= new Exercise(); 
      ex.WorkOutId=workoutID; 
      ex.WorkOut=db.WorkOuts(workoutID); 

      return View(ex); 
     } 

這看起來很糟糕,我在任何示例中都沒有看到類似的東西,但它似乎有效。同樣的練習對象會返回到我的POST創建動作

public ActionResult Create([Bind(Include = "Id,Name,WorkOutId")] Exercise exercise) 
     { 
      if (ModelState.IsValid) 
      { 
       db.Exercises.Add(exercise); 
       db.SaveChanges(); 
       return RedirectToAction("Create", "RepUnits", new { exerciseId = exercise.Id }); 
      } 
      return View(exercise); 
     } 

您看到的將調用RepUnits控制器和關聯的Create操作。我做了一些非常相似的事情。創建一個代表對象,並將其傳遞給視圖,基本上我添加代表直到完成。最後,我將創建導航,以返回添加新練習或返回到索引視圖。

所以總結一下,傳遞整個對象似乎是浪費,也許我的整個實現是錯誤的,我應該試圖以某種方式在一個表單上完成這一切。至此谷歌搜索沒有找到我很多,因爲我不知道有什麼問題要問,但是這個帖子Creation of objects using form data within an ASP.NET MVC application剛剛彈出在類似的問題對話和應用程序是巧合非常相似!然而,當OP提到通過鍛鍊周圍時,這是如何同時發生的?我想也許使用ViewBag,但我如何得到視圖來處理這個ID? 我雖然嘗試,作爲一個例子

public ActionResult Create(int workoutId) 
     { 
      ViewBag.WoID = workoutId; 
      return View(); 
     } 
在ExercisesController

,然後在相應的創建視圖:

@Html.Hidden("WorkOutId", new { ViewBag.WoID }) 

但後來在視圖中,當我嘗試引用鍛鍊日期說到空白

<div class="form-group"> 
      @Html.LabelFor(model => model.WorkOut.Date, "Work Out On:", htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.DisplayFor(model=>model.WorkOut.Date) 
      </div> 
     </div> 

我應該做這樣的事情的看法: @ Model.WorkOutId = ViewBag.WoID;

哪些工作出於某種原因(編譯器錯誤信息:CS1525:無效的表達式'='),但是我是如何傳遞這些id的?

+0

嘗試'@ {Model.Foo = ViewBag.Bar; },因爲你需要'@'來表示一個代碼塊而不是* print-here *操作符。 –

+0

當我嘗試,我的表單中, @using(Html.BeginForm()){ @ Html.AntiForgeryToken() @ Html.Hidden( 「WorkOutId」,新{} ViewBag.WoID) @ { Model.WorkOutId = ViewBag.WoID; }我得到解析器錯誤消息:「@」字符後出現意外的「{」。 Outisde的形式,我得到一個空例外錯誤 – greedyLump

回答

0

腳手架的意見是故意簡單化。處理相關的項目需要多方面的考慮,Visual Studio不會爲你製作這些項目。但是,您可以並且非常鼓勵您根據您的特定需求更改腳手架視圖。

要在與鍛鍊相同的視圖中創建練習,例如只需要生成Exercise的字段,其名稱將允許模型綁定器綁定發佈的數據。對於類似CollectionProperty[N].Property的收集屬性,其中N是索引。

例如,您可以用三個練習初始化你的鍛鍊:

var model = new Workout 
{ 
    ExerciseList = new List<Exercise> 
    { 
     new Exercise(), 
     new Exercise(), 
     new Exercise() 
    } 
}; 

然後,在你的看法:

@for (var i = 0; i < Model.Exercises.Count(); i++) 
{ 
    @Html.EditorFor(m => m.ExerciseList[i].Name) 
} 

然而,有一兩件事,這裏要注意:ICollection不是可轉位。因此,要這樣做,您需要一個類型爲List<Exercise>的屬性。這是視圖模型非常方便的地方。不過,有一種解決方法:您可以在Excercises集合上使用EditorFor。例如,上面的代碼將被減少到只有:

@Html.EditorFor(m => m.ExerciseList) 

EditorFor是一個「模板幫手」,這只是意味着它使用模板來呈現什麼傳遞給它。值得慶幸的是,它有一些默認設置,因此,您不必擔心這一點,但它會變得有問題。例如,在這裏,Razor將簡單地迭代ExerciseList中的項目併爲每個項目渲染Exercise的模板。由於Exercise是自定義類型,並且沒有默認模板,因此它將反思該類併爲Exercise上的每個公共屬性呈現模板。有時候這很好。例如,Name將使用文本框呈現,因爲它應該是。但是,您還會收到IdWorkoutId的文本框,您甚至不希望在表單上看到它們。

通過爲添加視圖,您可以通過爲Exercise創建自己的編輯器模板來解決此問題。這個視圖將有一個Exercise的模型,然後,只需爲您的名稱屬性添加一個文本框。然後,如上所述在ExerciseList上使用EditorFor時,它將使用該視圖渲染每個Exercise。儘管如此,你可能已經意識到這仍然是有限的:你必須用一定數量的練習進行初始化,然後這就是你所得到的。這就是JavaScript的用武之地。與其迭代預定義的練習列表,您可以根據需要動態添加新的練習字段(或刪除現有的字段)。但是,手動爲此任務編寫JavaScript將非常麻煩且密集。在這一點上,你最好利用像Knockout.js,Angular或類似的東西。這些庫除了別的以外,還提供了雙向數據綁定功能,因此您可以簡單地設置一個JavaScript模板來顯示練習字段的樣式,然後將其綁定到JavaScript對象的成員(您的客戶端 - 側面「視圖模型」)。然後你可以通過添加或刪除這個JS數組中的項來重複這些字段。顯然,還有更多這方面的內容,但這是基本框架。您需要查閱您所用庫的個別文檔,以確定如何設置所有內容。

然後,您可以沖洗並重復所有這些以用於其他級別的關係。換句話說,完全可以通過多個練習來發布鍛鍊的整個對象圖,每個練習都有多個代表單元等,所有這一切都在一個視圖中進行。

+0

TY爲您關注此。事實上,從預定義數量的練習開始將不起作用。但也許這告訴我我需要去的方向。我推遲了對JS的深入研究,但我猜想是時候了。 – greedyLump