If I want to set the DataSource property on a BindingSource to an IList<>, do I need an explicit cast as the following error message says or am I doing something wrong?
interface IView
{
IList<OrderItems> BindingSource { get; set;}
}
public partial class Form1 : Form, IView
{
public Form1()
{
InitializeComponent();
}
private BindingSource _bindingSource;
public IList<OrderItems> BindingSource
{
get { return _bindingSource; }
set
{
_bindingSource.DataSource = value;
dataGridView1.DataSource = _bindingSource;
}
}
}
OrderItems.cs
using System;
using System.Collections.Generic;
namespace Ordering.Data
{
/// <summary>
/// Order object for NHibernate mapped table 'Order'.
/// </summary>
[Serializable]
public class OrderItems
{
#region Member Variables
protected int _id;
protected Customers _customers;
protected string _ordername;
protected DateTime _orderdate;
protected DateTime? _shipdate;
protected string _shipvia;
protected string _shipname;
protected string _shipaddress;
protected string _shipcity;
protected string _shipregion;
protected string _shippostalcode;
protected string _shipcountry;
protected string _status;
protected DateTime? _lastupdate;
protected IList<Products> _products;
#endregion
#region Constructors
public OrderItems() {}
public OrderItems(Customers customers, string ordername, DateTime orderdate, DateTime? shipdate, string shipvia, string shipname, string shipaddress, string shipcity, string shipregion, string shippostalcode, string shipcountry, string status, DateTime? lastupdate)
{
this._customers= customers;
this._ordername= ordername;
this._orderdate= orderdate;
this._shipdate= shipdate;
this._shipvia= shipvia;
this._shipname= shipname;
this._shipaddress= shipaddress;
this._shipcity= shipcity;
this._shipregion= shipregion;
this._shippostalcode= shippostalcode;
this._shipcountry= shipcountry;
this._status= status;
this._lastupdate= lastupdate;
}
public OrderItems(Customers customers, string ordername, DateTime orderdate)
{
this._customers= customers;
this._ordername= ordername;
this._orderdate= orderdate;
}
#endregion
#region Public Properties
public virtual int Id
{
get { return _id; }
set { _id = value; }
}
public virtual Customers Customers
{
get { return _customers; }
set {_customers= value; }
}
public virtual string OrderName
{
get { return _ordername; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "OrderName cannot contain more than 255 characters");
if (value != this._ordername){_ordername= value;}}
}
public virtual DateTime OrderDate
{
get { return _orderdate; }
set {if (value != this._orderdate){_orderdate= value;}}
}
public virtual DateTime? ShipDate
{
get { return _shipdate; }
set {if (value != this._shipdate){_shipdate= value;}}
}
public virtual string ShipVia
{
get { return _shipvia; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipVia cannot contain more than 255 characters");
if (value != this._shipvia){_shipvia= value;}}
}
public virtual string ShipName
{
get { return _shipname; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipName cannot contain more than 255 characters");
if (value != this._shipname){_shipname= value;}}
}
public virtual string ShipAddress
{
get { return _shipaddress; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipAddress cannot contain more than 255 characters");
if (value != this._shipaddress){_shipaddress= value;}}
}
public virtual string ShipCity
{
get { return _shipcity; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipCity cannot contain more than 255 characters");
if (value != this._shipcity){_shipcity= value;}}
}
public virtual string ShipRegion
{
get { return _shipregion; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipRegion cannot contain more than 255 characters");
if (value != this._shipregion){_shipregion= value;}}
}
public virtual string ShipPostalcode
{
get { return _shippostalcode; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipPostalcode cannot contain more than 255 characters");
if (value != this._shippostalcode){_shippostalcode= value;}}
}
public virtual string ShipCountry
{
get { return _shipcountry; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "ShipCountry cannot contain more than 255 characters");
if (value != this._shipcountry){_shipcountry= value;}}
}
public virtual string Status
{
get { return _status; }
set {
if ( value != null && value.Length > 255)
throw new ArgumentOutOfRangeException("value", value.ToString(), "Status cannot contain more than 255 characters");
if (value != this._status){_status= value;}}
}
public virtual DateTime? LastUpdate
{
get { return _lastupdate; }
set {if (value != this._lastupdate){_lastupdate= value;}}
}
public virtual IList<Products> Products
{
get { return _products; }
set {_products= value; }
}
#endregion
#region Equals And HashCode Overrides
/// <summary>
/// local implementation of Equals based on unique value members
/// </summary>
public override bool Equals( object obj )
{
if( this == obj ) return true;
if( ( obj == null ) || ( obj.GetType() != this.GetType() ) ) return false;
OrderItems castObj = (OrderItems)obj;
return ( castObj != null ) &&
this._id == castObj.Id;
}
/// <summary>
/// local implementation of GetHashCode based on unique value members
/// </summary>
public override int GetHashCode()
{
int hash = 57;
hash = 27 * hash * _id.GetHashCode();
return hash;
}
#endregion
}
}
Cannot implicitly convert type 'System.Windows.Forms.BindingSource' to 'System.Collections.Generic.IList'. An explicit conversion exists (are you missing a cast?)
return _bindingSource.DataSource as IList<OrderItems>;
Related
I am working on REST API. I have JSON input in POST request contains many parameters of which one is user language.
JSON:
{
"userlanguage":"en"
}
I have created Enum class for all Languages.
Note: For reference I provided English, Hindi languages only.
public enum Language
{
EN = 0,
HI =1
}
To validate Class, I am using EnumDataType and Required data annotations.
public class UserDetails
{
[Required]
[EnumDataType(typeof(Language), ErrorMessage = "Invalid Language Supported.")]
[JsonProperty("userlanguage")]
public string? UserLanguage { get; set; }
}
I created Extension class to validate any class models.
public static class HttpRequestValidationExtension
{
public static bool IsValid(this object o, out ICollection<ValidationResult> validationResults)
{
validationResults = new List<ValidationResult>();
return Validator.TryValidateObject(o, new ValidationContext(o, null, null), validationResults, true);
}
}
Usage in Controller Class:
UserDetails userDetails= JsonConvert.DeserializeObject<UserDetails>(requestBody);
if (!userDetails.IsValid(validationResults: out var validationResults))
{
string errorMessage = "Bad Request.";
int statusCode = 400;
return DisplayErrorMessage
(statusCode,
string.Join("", validationResults.Select(s => s.ErrorMessage).FirstOrDefault()),
functionName,
string.Join("", validationResults.Select(s => s.MemberNames).FirstOrDefault()));
}
Problem:
If I supply EN my validation is SUCCESS. If I supply en my validation is FIALED.
Is there any way to ignore case?
After checked the source code of EnumDataType I think you could implement a custom EnumDataType to archive what you want.
So I change the EnumDataType to EnumIgnoreCaseDataTypeAttribute
public class UserDetails
{
[Required]
[EnumIgnoreCaseDataTypeAttribute(typeof(Language), ErrorMessage = "Invalid Language Supported.")]
[JsonProperty("userlanguage")]
public string? UserLanguage { get; set; }
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false)]
public class EnumIgnoreCaseDataTypeAttribute : DataTypeAttribute
{
public Type EnumType { get; private set; }
public EnumIgnoreCaseDataTypeAttribute(Type enumType)
: base("Enumeration")
{
this.EnumType = enumType;
}
public override bool IsValid(object value)
{
if (this.EnumType == null)
{
throw new InvalidOperationException();
}
if (!this.EnumType.IsEnum)
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "", this.EnumType.FullName));
}
if (value == null)
{
return true;
}
string stringValue = value as string;
if (stringValue != null && String.IsNullOrEmpty(stringValue))
{
return true;
}
Type valueType = value.GetType();
if (valueType.IsEnum && this.EnumType != valueType)
{
// don't match a different enum that might map to the same underlying integer
//
return false;
}
if (!valueType.IsValueType && valueType != typeof(string))
{
// non-value types cannot be converted
return false;
}
if (valueType == typeof(bool) ||
valueType == typeof(float) ||
valueType == typeof(double) ||
valueType == typeof(decimal) ||
valueType == typeof(char))
{
// non-integral types cannot be converted
return false;
}
object convertedValue;
if (valueType.IsEnum)
{
Debug.Assert(valueType == value.GetType(), "The valueType should equal the Type of the value");
convertedValue = value;
}
else
{
try
{
if (stringValue != null)
{
convertedValue = Enum.Parse(this.EnumType, stringValue, true);
}
else
{
convertedValue = Enum.ToObject(this.EnumType, value);
}
}
catch (ArgumentException)
{
//
return false;
}
}
if (IsEnumTypeInFlagsMode(this.EnumType))
{
string underlying = GetUnderlyingTypeValueString(this.EnumType, convertedValue);
string converted = convertedValue.ToString();
return !underlying.Equals(converted);
}
else
{
return Enum.IsDefined(this.EnumType, convertedValue);
}
}
private static bool IsEnumTypeInFlagsMode(Type enumType)
{
return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0;
}
private static string GetUnderlyingTypeValueString(Type enumType, object enumValue)
{
return Convert.ChangeType(enumValue, Enum.GetUnderlyingType(enumType), CultureInfo.InvariantCulture).ToString();
}
}
Source code reference: https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/EnumDataTypeAttribute.cs,4c23e1f3dcd51167
I am using DataAnnotations for validation of my ViewModel (WPF) so I can control the enable state of some buttons if the user type in a something that is not a float and if the value is outside of a range.
[Range(0, float.MaxValue, ErrorMessage = "StepSize must be more than 0")]
public float StepSize
{
get { return model.StepSize; }
set
{
model.StepSize = value;
RaisePropertyChangedAndRevalidate(nameof(StepSize));
}
}
private void RaisePropertyChangedAndRevalidate(string propertyName)
{
RaisePropertyChanged(propertyName);
if (_fieldBindingErrors == 0)
{
RaisePropertyChanged(nameof(IsValid));
}
}
private int _fieldBindingErrors = 0;
public ICommand RegisterFieldBindingErrors
{
get
{
return new RelayCommand<ValidationErrorEventArgs>(e =>
{
if (e.Action == ValidationErrorEventAction.Added)
{
_fieldBindingErrors++;
}
else
{
_fieldBindingErrors--;
}
RaisePropertyChanged(nameof(IsValid));
});
}
}
public bool IsValid
{
get
{
bool valid = Validator.TryValidateObject(this,
new ValidationContext(this, null, null),
new List<System.ComponentModel.DataAnnotations.ValidationResult>())
&& _fieldBindingErrors == 0;
return valid;
}
}
Problem is, when I convert the the textbox.Text string to a float I have to set the value to something not valid (should work for general cases also when the Range attribute is not in use). So I set the value to float.NaN.
The problem is that NaN seems to be a valid float, and it even passes the Range validation above.
Is there an attribute I could use to validate that the value is not NaN?
Found a solution, I created a custom validation rule instead and applied it in the XAML.
class StepSizeValidationRule : ValidationRule
{
private int _min;
private int _max;
public StepSizeValidationRule()
{
}
public int Min
{
get { return _min; }
set { _min = value; }
}
public int Max
{
get { return _max; }
set { _max = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
float stepSize = 0;
try
{
if (!float.TryParse(value.ToString(), out stepSize))
{
return new ValidationResult(false, "Not a float");
}
}
catch (Exception e)
{
return new ValidationResult(false, "Not a float " + e.Message);
}
if (float.IsNaN(stepSize))
{
return new ValidationResult(false, "Not a float ");
}
if ((stepSize < Min) || (stepSize > Max))
{
return new ValidationResult(false,
"Please enter a stepSize in the range: " + Min + " - " + Max + ".");
}
else
{
return new ValidationResult(true, null);
}
}
}
I used the below code for implementing Model in WPF. But the Problem is that it violates Solid Principle [Design Pattern] because model and validation code both are in the same code.
Help me out to separate them.
Employee Model-
public class EmployeeModel : Model
{
#region Fields
private int employeeId;
private string employeeCode;
private string firstName;
private string lastName;
private DateTime? dateOfJoining;
private DateTime dob;
private string email;
private int? departmentId;
private string departmentName;
private string password;
private string role;
#endregion
#region Public Properties
public int EmployeeId
{
get
{
return employeeId;
}
set
{
if (value != this.employeeId)
{
employeeId = value;
SetPropertyChanged("EmployeeId");
}
}
}
public string EmployeeCode
{
get
{
return employeeCode;
}
set
{
if (value != this.employeeCode)
{
employeeCode = value;
SetPropertyChanged("EmployeeCode");
}
}
}
public DateTime? DateOfJoining
{
get
{
return dateOfJoining;
}
set
{
if (value != this.dateOfJoining)
{
dateOfJoining = Convert.ToDateTime(value);
SetPropertyChanged("DateofJoining");
}
}
}
public string FirstName
{
get
{
return firstName;
}
set
{
if (value != this.firstName)
{
firstName = value;
SetPropertyChanged("FirstName");
}
}
}
public string LastName
{
get
{
return lastName;
}
set
{
if (value != this.lastName)
{
lastName = value;
SetPropertyChanged("LastName");
}
}
}
public string FullName
{
get
{
return string.Join(" ", new[] { firstName, lastName });
}
}
public int? DepartmentId
{
get
{
return departmentId;
}
set
{
if (value != this.departmentId)
{
departmentId = value;
SetPropertyChanged("DepartmentId");
}
}
}
public string DepartmentName
{
get
{
return departmentName;
}
set
{
if (value != this.departmentName)
{
departmentName = value;
SetPropertyChanged("DepartmentName");
}
}
}
public DateTime DOB
{
get
{
return dob;
}
set
{
if (value != this.dob)
{
dob = Convert.ToDateTime(value);
SetPropertyChanged("DateofBirth");
}
}
}
public string Email
{
get
{
return email;
}
set
{
if (value != this.email)
{
email = value;
SetPropertyChanged("Email");
}
}
}
public string Password
{
get
{
return password;
}
set
{
if (value != this.password)
{
password = value;
SetPropertyChanged("Password");
}
}
}
public string Role
{
get
{
return role;
}
set
{
if (value != this.role)
{
role = value;
SetPropertyChanged("Role");
}
}
}
#endregion
#region Private Methods
private bool IsValid(string emailaddress)
{
try
{
MailAddress m = new MailAddress(emailaddress);
return true;
}
catch (Exception)
{
return false;
}
}
#endregion
#region Public Methods
public override string GetErrorForProperty(string propertyName)
{
string retErrorMsg = string.Empty;
switch (propertyName)
{
case "EmployeeCode":
if (EmployeeCode == null || EmployeeCode.Length < 2)
{
retErrorMsg = AppConstants.EmpCodeError;
}
break;
case "FirstName":
if (FirstName == null || FirstName == string.Empty)
{
retErrorMsg = AppConstants.FNameError;
}
break;
case "LastName":
if (LastName == null || LastName == string.Empty)
{
retErrorMsg = AppConstants.LNameError;
}
break;
case "DepartmentId":
if (DepartmentId == null || DepartmentId < 1)
{
retErrorMsg = AppConstants.DepartmentError;
}
break;
case "DOB":
if (DOB.AddYears(60).Date < DateTime.Now.Date || DOB.AddYears(18).Date > DateTime.Now.Date)
{
retErrorMsg = AppConstants.DOBError;
}
break;
case "DateOfJoining":
if (DateOfJoining == null || DateOfJoining > DateTime.Now)
{
retErrorMsg = AppConstants.DOJError;
}
break;
case "Role":
if (!(Role == "A" || Role == "U"))
{
retErrorMsg = AppConstants.RoleError;
}
break;
case "Email":
if (!IsValid(Email))
{
retErrorMsg = AppConstants.EmailError;
}
break;
case "Password":
if ((Password == null || Password.Length < 8))
{
retErrorMsg = AppConstants.PasswordError;
}
break;
}
return retErrorMsg;
}
#endregion
}
Base Class[Model.cs]
public abstract class Model : INotifyPropertyChanged, IDataErrorInfo
{
public event PropertyChangedEventHandler PropertyChanged;
public void SetPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public string Error
{
get { return string.Empty; }
}
public string this[string propertyName]
{
get
{
return GetErrorForProperty(propertyName);
}
}
public abstract string GetErrorForProperty(string propertyName);
}
If you're worried about the S in Solid (Single Responsibility Principle), you should take a look at this answer: https://stackoverflow.com/a/597222/1685167
Basically, "The ViewModel single responsibility is to provide the View the information it needs." Personally I think you should be concerned with how the DataModel is unaware of the View more than anything else.
Here's a small example in code:
public class EmployeesEditViewModel : INotifyPropertyChanged
{
public string UserInputNewName
{
get
{
return Model.EmployeName;
}
set
{
if (ValidateValue(value))
{
Model.EmployeName = value;
ValidationResult = string.Empty;
OnPropertyChanged("UserInputNewName");
}
else
{
ValidationResult = "Error, name must not be empty.";
}
}
}
private bool ValidateValue(string value)
{
return !string.IsNullOrWhiteSpace(value);
}
private string _ValidationResult;
public string ValidationResult
{
get
{
return _ValidationResult ?? string.Empty;
}
set
{
_ValidationResult = value;
OnPropertyChanged("ValidationResult");
}
}
private EmployeeModel Model { get; set; }
}
public class EmployeeModel
{
public int EmployeeId { get; set; }
public string EmployeName { get; set; }
}
Explanation:
You have an EmployeeModel, this is the real model that describes an employee. Your view (for example a WPF Windows with user input fields) does not know about the model - there's no direct contact between model an view.
The view only knows about a view model. Suppose this is a mask that allows you to modify employees, then we'll use the EmployeesEditViewModel for that. The ViewModel exposes the properties needed for the view, in this simple case it's just the name of the employee and a valiation result (which could be just displayed in another text field). When the user enters a value, you can check if it's valid and then either update the actual model or tell the user what's wrong.
Ideally, you would probably have some validation logic on the model itself and have the ViewModel only transform this result into something that the user can see. This would keep all the responsibility (like validation) on the model where it belongs, but you'd still have a ViewModel that can translate and forward this to the View.
This is generic class to compare two objects with a user defined property, but it doesn't work correctly.
public class ObjectComparer<T> : IEqualityComparer<T>
{
private string _propertyName;
private string PropertyName
{
get { return _propertyName; }
set
{
_propertyName = value;
PropertyInfo = typeof(T).GetProperty(PropertyName);
}
}
public ObjectComparer(string propertyName)
{
PropertyName = propertyName;
}
private PropertyInfo PropertyInfo { get; set; }
public int GetHashCode(T type)
{
if (type== null)
{
return 0;
}
return PropertyInfo.GetHashCode();
}
public bool Equals(T obj1, T obj2)
{
if (ReferenceEquals(obj1, obj2))
{
return true;
}
if (ReferenceEquals(obj1, null) || ReferenceEquals(obj2, null))
{
return false;
}
return PropertyInfo.GetValue(obj1, null) == PropertyInfo.GetValue(obj2, null);
}
}
Issue 1)type == null (Possible compare of value type with null)
Issue 2)Use ReferenceEquals in this position is correct?
Update
"Word" class:
public class Word
{
public string EnglishText { get; set; }
public string LocalText { get; set; }
public string EditedText { get; set; }
}
Usage :
var except = Program.Localizer.DefaultLanguage.Words.Except(CurrentSelectedLanguage.Words, new ObjectComparer<Word>("EnglishText"));
Number of different objects based on the "EnglishName" is not correct.
Class authentic and Modified below.
Special thanks to Sriram Sakthivel
public class ObjectComparer<T> : IEqualityComparer<T>
{
private string _propertyName;
private string PropertyName
{
get { return _propertyName; }
set
{
_propertyName = value;
PropertyInfo = typeof(T).GetProperty(PropertyName);
}
}
public ObjectComparer(string propertyName)
{
PropertyName = propertyName;
}
private PropertyInfo PropertyInfo { get; set; }
public int GetHashCode(T obj)
{
if (ReferenceEquals(obj, null))
{
return 0;
}
return PropertyInfo.GetHashCode();
}
public bool Equals(T obj1, T obj2)
{
if (ReferenceEquals(obj1, obj2))
{
return true;
}
if (ReferenceEquals(obj1, null) || ReferenceEquals(obj2, null))
{
return false;
}
return Equals(PropertyInfo.GetValue(obj1, null),
PropertyInfo.GetValue(obj2, null));
}
}
Your GetHashCode is wrong. You're calling PropertyInfo.GetHashCode It should be using the Property value instead.
public int GetHashCode(T obj)
{
if (object.ReferenceEquals(obj, null))
{
return 0;
}
var value = PropertyInfo.GetValue(obj);
return value == null ? 0 : value.GetHashCode();
}
Also you can get rid of Possible compare of value type with null warning from resharper using object.ReferenceEquals
GetHashCode parameter is named as type, which is misleading, So I renamed it to obj
Update:
If you need to use value comparison you must use Object.Equals method as opposed to using == operator for object type
public bool Equals(T obj1, T obj2)
{
if (ReferenceEquals(obj1, obj2))
{
return true;
}
if (ReferenceEquals(obj1, null) || ReferenceEquals(obj2, null))
{
return false;
}
return object.Equals(PropertyInfo.GetValue(obj1, null),
PropertyInfo.GetValue(obj2, null));
}
public class MyClass
{
public string x;
public string y;
}
public class MyClassEqualityComparer : IEqualityComparer<MyClass>
{
public int GetHashCode(MyClass myobj)
{
if(myObj == null)
{
return base.GetHashCode();
}
if (myObj.x != null && myObj.y != null)
{
return myObj.x.GetGashCode()^myObj.y.GetGashCode();
}
}
}
what should be the implementation if myObj.x or/and myObj.y are nulls
The only requirement for a hash code is that two objects that are considered equal share the same hash code.
You can, for example, use 0 for null properties
public int GetHashCode(MyClass myobj)
{
if(myObj == null)
{
return base.GetHashCode();
}
return (myObj.x != null ? myObj.x.GetGashCode() : 0) ^ (myObj.y != null ? myObj.y.GetGashCode() : 0)
}