1

這是一直困惑着我最好的方法,同時保持可維護的代碼。下面的代碼爲支付網關表單設置一個月和年的列表,然後將它們分配給類型爲List<SelectListItem>的變量。MVC在ModelState.IsValid = false上設置Html.DropdownList

INTIAL行動

PayNowViewModel paymentGateway = new PayNowViewModel(); 
List<SelectListItem> paymentGatewayMonthsList = new List<SelectListItem>(); 
List<SelectListItem> paymentGatewayYearsList = new List<SelectListItem>(); 

for (int i = 1; i <= 12; i++) 
{ 
    SelectListItem selectListItem = new SelectListItem(); 
    selectListItem.Value = i.ToString(); 
    selectListItem.Text = i.ToString("00"); 

    paymentGatewayMonthsList.Add(selectListItem); 
} 

int year = DateTime.Now.Year; 
for (int i = year; i <= year + 10; i++) 
{ 
    SelectListItem selectListItem = new SelectListItem(); 
    selectListItem.Value = i.ToString(); 
    selectListItem.Text = i.ToString("00"); 

    paymentGatewayYearsList.Add(selectListItem); 
} 

paymentGateway.ExpiryMonth = paymentGatewayMonthsList; 
paymentGateway.ExpiryYear = paymentGatewayYearsList; 

return View(paymentGateway); 

它的代碼公平一點,我發現自己重複這個代碼,在類似的格式重新設置的下拉列表中選擇應ModelState.IsValid是假的,我想要返回到用戶糾正錯誤的視圖。

HttpPost行動 - 代碼

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult ConfirmPayment(PayNowViewModel paymentGatewayForm, FormCollection form) 
{ 
    if (ModelState.IsValid) 
    { 
     // Post processing actions... 
     return View(); 
    } 
    else 
    { 
     for (int i = 1; i <= 12; i++) 
     { 
      SelectListItem selectListItem = new SelectListItem(); 
      selectListItem.Value = i.ToString(); 
      selectListItem.Text = i.ToString("00"); 

      paymentGatewayMonthsList.Add(selectListItem); 
     } 

     int year = DateTime.Now.Year; 
     for (int i = year; i <= year + 10; i++) 
     { 
      SelectListItem selectListItem = new SelectListItem(); 
      selectListItem.Value = i.ToString(); 
      selectListItem.Text = i.ToString("00"); 

      paymentGatewayYearsList.Add(selectListItem); 
     } 

     form.ExpiryMonth = paymentGatewayMonthsList; 
     form.ExpiryYear = paymentGatewayYearsList; 

     return View("MakePayment", form); 
    } 
} 

什麼是集中顯示的下拉菜單設置代碼,以便其只在一個地方最好的方法是什麼?目前你會看到很大的比例(for循環),重複兩次。具有功能的基本控制器?還是像上面那樣重新設置會更好?

任何意見讚賞! Mike。

+0

因此,上面的代碼是一個算法,可以在整個項目中重複使用,但有一些細微差別? –

+0

這只是一個例子。該特定代碼片段被使用兩次,一次加載表單,並且如果ModelState無效(例如發送用戶返回以更改表單),則從post方法中重新加載表單。我有20個以上的實例,其下拉菜單是這樣設置的,然後在模型狀態失敗時再次重新設置,但是每個代碼和類都不同。 –

+1

您可以創建一個輔助類,它包含兩個靜態方法,GetPaymentMonthList和GetPaymentYearList,它返回適當的SelectListItem列表。然後你可以使用它而不用重寫它兩個地方。 –

回答

1

添加一個私有方法來你的控制器(下面的代碼假定您的ExpiryMonthExpiryYear性能IEnumerable<SelectListItem>這是所有的DropDownListFor()方法需要)

private void ConfigureViewModel(PayNowViewModel model) 
{ 
    model.ExpiryMonth = Enumerable.Range(1, 12).Select(m => new SelectListItem 
    { 
    Value = m.ToString(), 
    Text = m.ToString("00") 
    }); 
    model.ExpiryYear = Enumerable.Range(DateTime.Today.Year, 10).Select(y => new SelectListItem 
    { 
    Value = y.ToString(), 
    Text = y.ToString("00") 
    }); 
} 

然後在GET方法

public ActionResult ConfirmPayment() 
{ 
    PayNowViewModel model = new PayNowViewModel(); 
    ConfigureViewModel(model); 
    return View(model); 
} 

並在POST方法中

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult ConfirmPayment(PayNowViewModel model) 
{ 
    if (!ModelState.IsValid) 
    { 
    ConfigureViewModel(model); 
    return View(model); 
    } 
    .... // save and redirect (should not be returning the view here) 
} 
0

如果下拉選項的設置是固定的(或者在潛在選項更改後重新編譯是OK),則可以使用枚舉來存儲選項。

public enum Month { 
    // if the dropdown is not required, add default value 0 
    Optional = 0, 
    [Display(Name = @"Month_January")] 
    January = 1, 
    [Display(Name = @"Month_February")] 
    February = 2, 
    // etc .. 
} 

爲了使這是一個下拉使用EditorTemplate Enum.cshtml

@model Enum 
    @{ 
     var enumType = ViewData.ModelMetadata.ModelType; 
     var allValues = Enum.GetValues(enumType).Cast<object>().ToSelectList(Model); 
     // read any attributes like [Required] from ViewData and ModelMetadata ...     
     var attributes = new Dictionary<string, object>();  
    } 

    @Html.DropDownListFor(m => m, allValues, attributes) 

ToSelectList擴展方法遍歷所有的枚舉值,並將其轉換爲SelectListItems:

public static IList<SelectListItem> ToSelectList<T>(this IEnumerable<T> list) { 
     return ToSelectList<T>(list, list.FirstOrDefault()); 
    } 

    public static IList<SelectListItem> ToSelectList<T>(this IEnumerable<T> list, T selectedItem) { 
     var items = new List<SelectListItem>(); 
     var displayAttributeType = typeof(DisplayAttribute); 

     foreach (var item in list) { 
      string displayName; 

      // multi-language: 
      // assume item is an enum value 
      var field = item.GetType().GetField(item.ToString()); 
      try { 
       // read [Display(Name = @"someKey")] attribute 
       var attrs = (DisplayAttribute)field.GetCustomAttributes(displayAttributeType, false).First(); 
       // lookup translation for someKey in the Resource file 
       displayName = Resources.ResourceManager.GetString(attrs.Name); 
      } catch { 
       // no attribute -> display enum value name 
       displayName = item.ToString(); 
      } 

      // keep selected value after postback: 
      // assume selectedItem is the Model passed from MVC 
      var isSelected = false; 
      if (selectedItem != null) { 
       isSelected = (selectedItem.ToString() == item.ToString()); 
      } 

      items.Add(new SelectListItem { 
       Selected = isSelected, 
       Text = displayName, 
       Value = item.ToString() 
      }); 
     } 

     return items; 
    }  

爲了支持多個語言,爲顯示名稱鍵添加翻譯,例如"Month_January",以資源文件。現在

,使用一些反射魔法,創建一個新的視圖模型設置代碼已經被抽象出來是一件輕而易舉的事:>

public class PayNowViewModel { 
    // SelectListItems are only generated if this gets rendered 
    public Month ExpiryMonth { get; set; } 
} 

// Intial Action 
var paymentGateway = new PayNowViewModel(); 
return View(paymentGateway); 

// Razor View: call the EditorTemplate 
@Html.EditorFor(m => m.ExpiryMonth) 

注意,在EditorTemplate,Model作爲選定項目傳遞給ToSelectList。回發後,模型將保存當前選定的值。因此它會保持選定的,即使你只是返回模型中的錯誤後的控制器:

// HttpPost Action 
if (!ModelState.IsValid) { 
    return View("MakePayment", paymentGatewayForm); 
} 

我們花了一些時間來想出了這個解決方案,學分轉到Saratiba隊。

相關問題