2011-06-21 11 views
23

Czy można umieścić atrybut [Wymagany] na liście Właściwości listy?Wymagany atrybut na ogólnej liście właściwości

Wiążę się z ogólną listą na POST i zastanawiałem się, czy mogę spowodować, że funkcja ModelState.IsValid() nie powiedzie się, jeśli właściwość zawiera 0 elementów?

+0

Jeżeli zmienisz swój model w użyciu tablicę zamiast listy można użyć [MinLengthAttribute ] (https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.minlengthattribute%28v=vs.110%29.aspx) – janv8000

Odpowiedz

27

Dodanie atrybutu Required do właściwości stylu listy tak naprawdę nie robi tego, co chcesz. Osoba składająca skargę złoży skargę, jeżeli lista nie zostanie utworzona, ale nie będzie narzekała, jeśli lista zawiera 0 pozycji.

Należy jednak być dość łatwe do uzyskania przypisywać własne adnotacje danych i uczynić go sprawdzić listę dla Count> 0. coś takiego jeszcze nie (sprawdzone)

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CannotBeEmptyAttribute : ValidationAttribute 
{ 
    private const string defaultError = "'{0}' must have at least one element."; 
    public CannotBeEmptyAttribute () : base(defaultError) // 
    { 
    } 

    public override bool IsValid (object value) 
    { 
     IList list = value as IList; 
     return (list != null && list.Count > 0); 
    } 

    public override string FormatErrorMessage (string name) 
    { 
     return String.Format(this.ErrorMessageString, name); 
    } 
} 

EDIT:

Należy również zachować ostrożność w sposobie wiązania listy w widoku. Na przykład, jeśli wiążą List<String> do widoku tak:

<input name="ListName[0]" type="text" /> 
<input name="ListName[1]" type="text" /> 
<input name="ListName[2]" type="text" /> 
<input name="ListName[3]" type="text" /> 
<input name="ListName[4]" type="text" /> 

Model spoiwo MVC będzie zawsze umieścić 5 elementów w liście, wszystkie String.Empty. Jeśli tak działa Twój widok, Twój atrybut musiałby być nieco bardziej złożony, na przykład za pomocą Reflection, aby pobrać typowy parametr i porównać każdy element listy z czymś w rodzaju: default(T).

Lepszą alternatywą jest użycie jQuery do dynamicznego tworzenia elementów wejściowych.

+0

Nie sądzę, że mógłbyś [rozwinąć tę edycję] (https://stackoverflow.com/questions/45201531/cant-force-listint-to-be-bequired)? – Sinjai

+0

Nie jestem pewien, o którą edycję pytasz ... Twój link prowadzi do pytania. –

+0

Tak, pytanie jest (potencjalnie - częściowo o to pytam) powiązane. – Sinjai

20

Dla tych, którzy szukasz minimalistycznych przykładów:

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CannotBeEmptyAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     var list = value as IEnumerable; 
     return list != null && list.GetEnumerator().MoveNext(); 
    } 
} 

To jest zmodyfikowany kod z przyjętą odpowiedzi. Jest odpowiedni w przypadku od pytania, aw jeszcze większej liczbie przypadków, ponieważ IEnumerable jest wyższy w hierarchii System.Collections. Ponadto dziedziczy zachowanie z RequiredAttribute, więc nie ma potrzeby kodowania go jawnie.

+0

Najbardziej podstawowe rozwiązanie, dzięki! –

1

Modified realizacja @moudrick dla mojego wymogu

Atrybut Wymagane Zatwierdzenie przez liście, a pole wyboru Lista

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CustomListRequiredAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     var list = value as IEnumerable; 
     return list != null && list.GetEnumerator().MoveNext(); 
    } 
} 

Jeśli masz listę checkbox

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CustomCheckBoxListRequiredAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     bool result = false; 

     var list = value as IEnumerable<CheckBoxViewModel>; 
     if (list != null && list.GetEnumerator().MoveNext()) 
     { 
      foreach (var item in list) 
      { 
       if (item.Checked) 
       { 
        result = true; 
        break; 
       } 
      } 
     } 

     return result; 
    } 
} 

Oto moja Widok Model

public class CheckBoxViewModel 
{   
    public string Name { get; set; } 
    public bool Checked { get; set; } 
} 

Wykorzystanie

[CustomListRequiredAttribute(ErrorMessage = "Required.")] 
public IEnumerable<YourClass> YourClassList { get; set; } 

[CustomCheckBoxListRequiredAttribute(ErrorMessage = "Required.")] 
public IEnumerable<CheckBoxViewModel> CheckBoxRequiredList { get; set; } 
2

Dla tych, które używają C# 6.0 i którzy poszukują jednej wkładki:

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CannotBeEmptyAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false; 
} 
Powiązane problemy