Как правильно проверить свойство коллекцию на правильность ввода!
Мне нужно проверать все свойства класса OfferModel.
Проблема в том что нужно проверить:Picture,Descriptions,Param как это коллекции а не свойства.
Например:как проверить свойство коллекцию Descriptions.Text на пустоту(то есть пользователь ввел данные все ок если это не так textbox становиться крассый я это делаю спомощью IDataErrorInfo) и проверить коллекции есть элементы Descriptions.Count()>0 тогда кнопка выключена.
То есть если Descriptions.Count()>0 в коллекции больше 0 элементов и если элементы все свойства пустые Descriptions.Text деактивировать кнопку или Descriptions.Count() != 0 и все свойства Descriptions.Text не пустые активировать кнопку.
Этот пример я использовал для проверки валидации данных У меня есть модели коллекции и я не знаю как проверять на валидацию данных.
OfferModel
class OfferModel:ChangeProperty,IDataErrorInfo
{
#region Cвойства
string url { get; set; }
public string Url
{
get { return url; }
set
{
url = value;
OnPropertyChanged("Url");
}
}
decimal price { get; set; }
public decimal Price
{
get { return price; }
set
{
price = value;
OnPropertyChanged("Price");
}
}
string currencyId { get; set; }
public string CurrencyId
{
get { return currencyId; }
set
{
currencyId = value;
OnPropertyChanged("CurrencyId");
}
}
int categoryId { get; set; }
public int CategoryId
{
get { return categoryId; }
set
{
categoryId = value;
OnPropertyChanged("CategoryId");
}
}
public ObservableCollection<string> Picture { get; set; } = new ObservableCollection<string>();
string name { get; set; }
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
string vendor { get; set; }
public string Vendor
{
get { return vendor; }
set
{
vendor = value;
OnPropertyChanged("Vendor");
}
}
public ObservableCollection<DescriptionModel> Descriptions { get; set; } = new ObservableCollection<DescriptionModel>();
public ObservableCollection<ParamModel> Param { get; set; } = new ObservableCollection<ParamModel>();
int stock_quantity { get; set; }
public int Stock_quantity
{
get { return stock_quantity; }
set
{
stock_quantity = value;
OnPropertyChanged("Stock_quantity");
}
}
bool аvailable { get; set; }
public bool Available
{
get { return аvailable; }
set
{
аvailable = value;
OnPropertyChanged("Available");
}
}
int id { get; set; }
public int Id
{
get { return id; }
set
{
id = value;
OnPropertyChanged("Id");
}
}
#endregion
#region Проверка свойств
string er { get; set; }
public string Error
{
get { return er; }
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "Name":
validationResult = Validation.Name(Name);
break;
case "Url":
validationResult = Validation.Ui(Url);
break;
case "Price":
validationResult = Validation.Price(Price);
break;
case "Vendor":
validationResult = Validation.Vendor(Vendor);
break;
case "Stock_quantity":
validationResult = Validation.StockQuantity(Stock_quantity);
break;
default:throw new ApplicationException("Неизвестное свойство проверяется модели OfferModel.");
}
return validationResult;
}
}
#endregion
public OfferModel(){}
public OfferModel(string url, decimal price, string currencyId, int categoryId, string name, string vendor, int stock_quantity, bool available, int id)
{
Url = url;
Price = price;
CurrencyId = currencyId;
CategoryId = categoryId;
Name = name;
Vendor = vendor;
Stock_quantity = stock_quantity;
Available = available;
Id = id;
}
}
ParamModel
class ParamModel :ChangeProperty,IDataErrorInfo
{
string name { get; set; }
string text { get; set; }
/// <summary>
/// Xарактеристику параметра.
/// </summary>
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
/// <summary>
/// Значение параметра.
/// </summary>
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged("Text");
}
}
public ParamModel() { }
public ParamModel(string name, string text)
{
Name = name;
Text = text;
}
#region Проверка свойств
string er { get; set; }
public string Error
{
get { return er; }
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "Name":
validationResult = Validation.NameParam(Name);
break;
case "Text":
validationResult = Validation.TextParam(Text);
break;
default:throw new ApplicationException("Неизвестное свойство проверяется модели ParamModel.");
}
return validationResult;
}
}
#endregion
}
DescriptionModel
class DescriptionModel:ChangeProperty,IDataErrorInfo
{
private string text { get; set; }
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged(nameof(Text));
}
}
public DescriptionModel() { }
public DescriptionModel(string text)
{
Text = text;
}
#region Проверка свойств
string er { get; set; }
public string Error
{
get { return er; }
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "Text":
validationResult = Validation.Text(Text);
break;
default: throw new ApplicationException("Неизвестное свойство проверяется модели DescriptionModel.");
}
return validationResult;
}
}
#endregion
}
Как я проверяю AddProductViewModel свойство коллекцию при дабавлении товара: Picture.CollectionChanged-при добавлении в коллекцию,item.PropertyChanged-при изменении свойств.
Это хорошо когда событие сработало CollectionChanged(то есть при добавлении в коллекцию,ну если offer передать по ссылке в конструктор для измерения товара событие не сработает CollectionChanged).
Есть другой способ реализации проверки?
readonly OfferModel offer;
/// <summary>
/// Хранения валлидность свойств.
/// </summary>
private Dictionary<string, bool> validProperties;
/// <summary>
/// Включить кнопку если все свойства валлидни.
/// </summary>
private bool allPropertiesValid = false;
public bool AllPropertiesValid
{
get { return allPropertiesValid; }
set
{
if (allPropertiesValid != value)
{
allPropertiesValid = value;
OnPropertyChanged("AllPropertiesValid");
}
}
}
#region Валидации данных
validProperties = new Dictionary<string, bool>();//нужен для того чтобы включить кнопку добавленные если все данные будут коректные.
validProperties.Add("Name", false);
validProperties.Add("Url", false);
validProperties.Add("Price", false);
validProperties.Add("Vendor", false);
validProperties.Add("Stock_quantity", false);
validProperties.Add("Picture", false);
validProperties.Add("Descriptions", false);
validProperties.Add("Param", false);
//Проверки на валидность ввода Picture Descriptions Param.
Picture.CollectionChanged += (s, e) =>
{
validProperties["Picture"] = Picture.Count() > 0 ? true : false;
ValidateProperties();
};
Descriptions.CollectionChanged += (s, e) =>
{
bool isEmpty = false;
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (DescriptionModel item in e.NewItems)//Добавление новые элементы
{
isEmpty = Validation.TextBool(item.Text) ? false : true;
item.PropertyChanged += (sender, argument) => //Проходимся по свойствам модели.
{
int i = 0;
foreach (var des in Descriptions)
{
if (Validation.TextBool(des.Text))
{
i++;
}
}
validProperties["Descriptions"] = (i == 0) ? true : false;
isEmpty = (i == 0) ? true : false;
ValidateProperties();
};
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
int i = 0;
foreach (var des in Descriptions)
{
if (Validation.TextBool(des.Text))
{
i++;
}
}
isEmpty = (i == 0) ? true : false;
}
validProperties["Descriptions"] = (Descriptions.Count > 0 && isEmpty != false) ? true : false;
ValidateProperties();
};
Param.CollectionChanged += (s, e) =>
{
bool isEmpty = false;
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (ParamModel item in e.NewItems)//Добавление новые элементы
{
var name = Validation.NameBoolParam(item.Name);
var text = Validation.TextBoolParam(item.Text);
validProperties["Param"] = (name && text) ? false: true;
item.PropertyChanged += (sender, argument) => //Проходимся по свойствам модели.
{
int nameisvalid = 0;
int textisvalid = 0;
foreach (var par in Param)//Ищем неправильно заполнены параметры.
{
if (Validation.NameBoolParam(par.Name)) nameisvalid++;
if (Validation.TextBoolParam(par.Text)) textisvalid++;
}
validProperties["Param"] = (nameisvalid == 0 && textisvalid == 0) ? true : false;
isEmpty = (nameisvalid == 0 && textisvalid == 0) ? true : false;
ValidateProperties();
};
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
int nameisvalid = 0;
int textisvalid = 0;
foreach (var par in Param)
{
if (Validation.NameBoolParam(par.Name)) nameisvalid++;
if (Validation.TextBoolParam(par.Text)) textisvalid++;
}
isEmpty = (nameisvalid == 0 && textisvalid == 0) ? true : false;
}
validProperties["Param"] = (Param.Count > 0 && isEmpty != false) ? true : false;
ValidateProperties();
};
#endregion
#region Реализация IDataErrorInfo
public string Error
{
get { return (offer as IDataErrorInfo).Error; }
}
public string this[string propertyName]
{
get
{ if(offer != null)
{
string error = (offer as IDataErrorInfo)[propertyName];
validProperties[propertyName] = string.IsNullOrEmpty(error) ? true : false;
ValidateProperties();
CommandManager.InvalidateRequerySuggested();
return error;
}
return null;
}
}
private void ValidateProperties()
{
foreach (bool isValid in validProperties.Values)
{
if (!isValid)
{
AllPropertiesValid = false;
return;
}
}
AllPropertiesValid = true;
}
#endregion
Ответы (1 шт):
Для этих целей существуют атрибуты ValidationAttribute. Если необходимо реализовать какую-либо особенную проверку свойства, то можно:
- создать свой атрибут
- реализовать интерфейс IValidatableObject для проверки всего типа. В этом случае можно будет использовать Validator.
- использовать CustomValidationAttribute для вызова статического метода с сигнатурой:
- ValidationResult Method(object)
- ValidationResult Method(object, ValidationContext)
После этого мы можем использовать рефлексию для проверки. Использование может выглядеть так:
public static class StaticValidators
{
public static ValidationResult IsUpperCase(object value, ValidationContext context)
{
if (value is null)
{
return new ValidationResult(Res.IsUpper_ValueIsNull, new string[] { context.MemberName });
}
string strValue = value.ToString();
if (string.IsNullOrWhiteSpace(strValue))
{
return new ValidationResult(Res.IsUpper_ValueIsEmpty, new string[] { context.MemberName });
}
bool _isEquals = string.Equals(strValue, strValue.ToUpperInvariant(), StringComparison.InvariantCulture);
return _isEquals
? ValidationResult.Success
: new ValidationResult(Res.IsUpper_ValueIsNotValid, new string[] { context.MemberName });
}
}
public class Person
{
[Required(AllowEmptyStrings = false),
StringLength(10),
RegularExpression(@"^[a-zA-Z-]+$")]
public string FirstName { get; set; }
[Required(AllowEmptyStrings = false),
StringLength(10),
RegularExpression(@"^[a-zA-Z-]+$")]
public string LastName { get; set; }
public string MiddleName { get; set; }
[Required(AllowEmptyStrings = false),
CustomValidation(typeof(StaticValidators), method: nameof(StaticValidators.IsUpperCase))]
public string PersonalNr { get; set; }
[ContainsUnique(typeof(string))]
public List<string> Emails { get; set; }
[ContainsUnique(typeof(PhoneNumber), PropertyName = nameof(PhoneNumber.TypeOfPhone))]
public List<PhoneNumber> Phones { get; set; }
}
public struct PhoneNumber
{
public string NumberOfPhone { get; set; }
public PhoneType TypeOfPhone { get; set; }
}
var person = new Person
{
FirstName = "John",
LastName = "Doe",
PersonalNr = "Abc123",
Emails = new List<string>
{
"[email protected]", "[email protected]", "[email protected]", "[email protected]"
},
Phones = new List<PhoneNumber>
{
new PhoneNumber{ NumberOfPhone = "123", TypeOfPhone = PhoneType.PrivateMobile },
new PhoneNumber{ NumberOfPhone = "567", TypeOfPhone = PhoneType.PrivateMobile }
}
};
var result = person.ValidateType();
/*
result is:
[{
"PropertyName": "PersonalNr",
"AttributeName": "RegularExpressionAttribute",
"ErrorMessage": "The field PersonalNr must match the regular expression '^[a-zA-Z]{2}[0-9]{5}$'."
},
{
"PropertyName": "Emails",
"AttributeName": "ContainsUniqueAttribute",
"ErrorMessage": "Поле Emails не должно содержать повторяющихся значений в свойстве 'value'. Дубликаты значений: [email protected]."
},
{
"PropertyName": "Phones",
"AttributeName": "ContainsUniqueAttribute",
"ErrorMessage": "Поле Phones не должно содержать повторяющихся значений в свойстве 'TypeOfPhone'. Дубликаты значений: PrivateMobile."
}]
*/
Пример реализации атрибута валидации:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public sealed class MinCountAttribute : ValidationAttribute
{
public uint MinCount { get; }
public MinCountAttribute(uint minCount)
{
MinCount = minCount;
ErrorMessageResourceType = typeof(AttributesResources);
ErrorMessageResourceName = nameof(AttributesResources.MinCount_ValidationError);
}
public override string FormatErrorMessage(string name)
{
return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MinCount);
}
public override bool IsValid(object value)
{
if (value is null)
{
return false;
}
if (value is ICollection collection)
{
return MinCount <= (collection?.Count ?? -1);
}
throw new InvalidCastException(AttributesResources.MinCount_InvalidCastException);
}
}
Ссылки по теме
- демо-проект
- IValidatableObject Interface
- ValidationAttribute Class
- CustomValidationAttribute Class
- исходный код CustomValidationAttribute.cs
P.S.: извиняюсь. Только сейчас понял, что речь идёт о WPF. В таком случае вот этот ответ поможет.